When we write a placement version of operator new, be sure to write the corresponding placement version of operator delete to avoid subtle, intermittent memory leaks. When we do so, pay attention not to unintentionally hide the normal versions of new and delete
Placement version of new
When an operator new function takes extra parameters (other than the mandatory size_t argument), that function is known as a placement version of new. For example:
|
|
This specific version of placement new is in C++’s standard library (access through #include<new>) and is the original placement new. Later, people also use the term “placement new” to refer any version of operator new that takes extra arguments. The phrace “placement delete” also derives from this version.
To avoid subtle memory leak
Suppose we want to write a class-specific operator new that requires specification of an ostream to which allocation information should be logged:
|
|
And we call it this to log allocation informatino to cerr when dynamically creating a Wdiget:
|
|
Let’s consider a special subtle situation: if memory allocation succeeds and the Widget constructor throws an exception, since pw not yet assigned and client code can’t deallocate the memory, the runtime system is responsible for undoing the allocation that operator new performed. However, we’re now using a non-normal version of operator new, unless it finds a version of operator delete that takes the same number and types of extra arguments as operator new, the runtime system choose to do nothing, so no operator delete will be called, ending up with memory leak.
To eliminate the memory leak in this situation, we need to match the placement new with a placement delete:
|
|
Now following code will work without leak:
|
|
Do not hide normal form of new and delete
By default, C++ offers the following forms of operator new (and corresponding operator delete) at global scope:
|
|
According to item 33, member function names hide functions with the same names in outer scopes, so we want to avoid having class-specific news hide other news that our client expect. For example, if the base class declares only a placement new, clients will find the normal version of new unavailable:
|
|
Similarly, redeclaring operator new in derived classes hide both global and inherited versions of operator new:
|
|
In order to make normal version of operator new accessible in addition to customed ones, we need to declare all forms (both standard version and placement version) in our class. If we want class-specific standard versions to behave in the usual way, just have the them call the global versions. An easy way to do this is to create a base class containing all the normal forms of new and delete:
|
|
Clients who want to augment the standard forms with custom forms can just use inheritance and using declarations (item 33) to get all forms accessible:
|
|