Overloading new & delete
When you create a
new-expression, two things occur. First, storage is
allocated using the operator new( ), then the constructor is
called. In a delete-expression, the destructor is
called, then storage is deallocated using the operator delete( ).
The constructor and destructor calls are never under your control (otherwise you
might accidentally subvert them), but you can change the storage
allocation functions operator new( ) and operator delete(
).
The memory allocation
system used by new and
delete is designed for general-purpose use. In special situations,
however, it doesn’t serve your needs. The most common reason to change the
allocator is efficiency: You might be creating and
destroying so many objects of a particular class that it has become a speed
bottleneck. C++ allows you to overload new and delete to implement
your own storage allocation scheme, so you can handle problems like
this.
Another issue is
heap fragmentation. By
allocating objects of different sizes it’s possible to break up the heap
so that you effectively run out of storage. That is, the storage might be
available, but because of fragmentation no piece is big enough to satisfy your
needs. By creating your own allocator for a particular class, you can ensure
this never happens.
In embedded and real-time systems, a
program may have to run for a very long time with restricted resources. Such a
system may also require that memory allocation always take the same amount of
time, and there’s no allowance for heap exhaustion or fragmentation. A
custom memory allocator is the solution; otherwise, programmers will avoid using
new and delete altogether in such cases and miss out on a valuable
C++ asset.
When you overload operator new(
) and operator delete( ), it’s important to remember
that you’re changing only the way raw storage is allocated. The
compiler will simply call your new instead of the default version to
allocate storage, then call the constructor for that storage. So, although the
compiler allocates storage and calls the constructor when it sees
new, all you can change when you overload new is the storage
allocation portion. (delete has a similar limitation.)
When you overload operator
new( ), you also replace the behavior when it runs out of memory,
so you must decide what to do in your operator new( ): return
zero, write a loop to call the new-handler and retry allocation, or (typically)
throw a bad_alloc exception (discussed in Volume 2, available at
www.BruceEckel.com).
Overloading new and delete
is like overloading any other operator. However, you have a choice of
overloading the global allocator or using a different allocator for a particular
class.