Also available at

Also available at my website http://tosh.me/ and on Twitter @toshafanasiev

Tuesday, 24 January 2012

Overloading new and delete in C++

While writing C++ you might want to be involved in the details of dynamically allocated memory yourself; to ensure that certain types of object sit together in memory; to minimise space wasted on overhead for arrays of small objects; to improve allocation speed (at the cost of memory held) or to satisfy a fixed memory requirement. Whatever the reason (and once the trade-offs are fully understood), the basic plumbing you would need looks something like this:
#include <iostream>

using std::cout;
using std::endl;

class Thing {
public:
  Thing() {
    cout << "new Thing: " << sizeof( Thing ) << " bytes" << endl;
  }
  ~Thing() {
    cout << "~Thing()" << endl;
  }
  static void* operator new( size_t size ) {
    cout << "allocating " << size << " bytes in operator new" << endl;

    return ::operator new( size );
  }
  static void operator delete( void* mem ) {
    cout << "operator delete" << endl;

    ::operator delete( mem );
  }
  static void* operator new[]( size_t size ) {
    cout << "allocating " << size << " bytes in operator new[]" << endl;

    return ::operator new[]( size );
  }
  static void operator delete[]( void* mem ) {
    cout << "operator delete[]" << endl;

    ::operator delete[]( mem );
  }
private:
  unsigned char value_;
  // not worrying about copy/move for this example
  Thing( const Thing& );
  Thing( Thing&& );
  void operator=( const Thing& );
  void operator=( Thing&& );
};

int main( int argc, char* argv[] ) {

  cout << "creating an object ..." << endl;
  auto* t = new Thing;

  delete t;

  const int SIZE = 5;
  cout << "creating a " << SIZE << " element array ..." << endl;
  auto* a = new Thing[SIZE];

  delete[] a;

  return 0;
}

In this example my overloaded operators defer to the default provided versions, so nothing really interesting is being done in terms of memory allocation, but it does serve as an illustration of the mechanism, as the output shows:
creating an object ...
allocating 1 bytes in operator new
new Thing: 1 bytes
~Thing()
operator delete
creating a 5 element array ...
allocating 9 bytes in operator new[]
new Thing: 1 bytes
new Thing: 1 bytes
new Thing: 1 bytes
new Thing: 1 bytes
new Thing: 1 bytes
~Thing()
~Thing()
~Thing()
~Thing()
~Thing()
operator delete[]
It also illustrates the importance of pairing up the scalar and vector forms of new and delete properly - the additional 4 bytes allocated for the array are for tracking the size of the array for deletion - using the wrong form of delete causes that information to be ignored/erroneously read, depending on which way round you get it wrong.

No comments:

Post a comment