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 new
s hide other new
s 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:
|
|