The operator delete Function
Memory that is dynamically allocated using the new operator can be freed using the delete operator. The delete operator calls the operator delete function, which frees memory back to the available pool. Using the delete operator also causes the class destructor (if there is one) to be called.
There are global and class-scoped operator delete functions. Only one operator delete function can be defined for a given class; if defined, it hides the global operator delete function. The global operator delete function is always called for arrays of any type.
The global operator delete function, if declared, takes a single argument of type void *, which contains a pointer to the object to deallocate. The return type is void (operator delete cannot return a value). Two forms exist for class-member operator delete functions:
void operator delete( void * );
void operator delete( void *, size_t );
Only one of the preceding two variants can be present for a given class. The first form works as described for global operator delete. The second form takes two arguments, the first of which is a pointer to the memory block to deallocate and the second of which is the number of bytes to deallocate. The second form is particularly useful when an operator delete function from a base class is used to delete an object of a derived class.
The operator delete function is static; therefore, it cannot be virtual. The operator delete function obeys access control, as described in Chapter 10, Member-Access Control.
The following example shows user-defined operator new and operator delete functions designed to log allocations and deallocations of memory:
#include <iostream.h>
#include <stdlib.h>
int fLogMemory = 0; // Perform logging (0=no; nonzero=yes)?
int cBlocksAllocated = 0; // Count of blocks allocated.
// User-defined operator new.
void *operator new( size_t stAllocateBlock )
{
static fInOpNew = 0; // Guard flag.
if( fLogMemory && !fInOpNew )
{
fInOpNew = 1;
clog << "Memory block " << ++cBlocksAllocated
<< " allocated for " << stAllocateBlock
<< " bytes\n";
fInOpNew = 0;
}
return malloc( stAllocateBlock );
}
// User-defined operator delete.
void operator delete( void *pvMem )
{
static fInOpDelete = 0; // Guard flag.
if( fLogMemory && !fInOpDelete )
{
fInOpDelete = 1;
clog << "Memory block " << --cBlocksAllocated
<< " deallocated\n";
fInOpDelete = 0;
}
free( pvMem );
}
int main( int argc, char *argv[] )
{
fLogMemory = 1; // Turn logging on.
if( argc > 1 )
for( int i = 0; i < atoi( argv[1] ); ++i )
{
char *pMem = new char[10];
delete[] pMem;
}
return cBlocksAllocated;
}
The preceding code can be used to detect “memory leakage” — that is, memory that is allocated on the free store but never freed. To perform this detection, the global new and delete operators are redefined to count allocation and deallocation of memory.
Beginning with Visual C++ 5.0, the compiler supports member array new and delete operators in a class declaration. For example:
class X {
public:
void* operator new[] (size_t);
void operator delete[] (void*);
};
void f() {
X *pX = new X[5];
delete [] pX;
}