The Problem with Placement New

A few days ago I posted about a wonderous operator I had just found out about, known as Placement New. However after playing around with it a bit, I came by a slight problem with it.

To understand it, lets look at the class below.

#ifndef TEST_H_INCLUDED
#define TEST_H_INCLUDED
 
// --- [ includes ] -------------------------------------------
//
#include <stdlib.h>
 
// --- [ class ] ----------------------------------------------
//
class Test
{
	// Attributes
	//
	private:
		void * m_pData;
 
	// Functions
	//
	public:
		Test()
		{
			m_pData = malloc( 100 );
		}
 
		~Test()
		{
			free( m_pData );
		}
};
 
#endif

 

A very basic class, in it’s constructor it allocates 100 bytes of memory and then frees that 100 bytes in its destructor, so no memory leak as long as the destructor is called. Now lets see this in action with placement new.

// --- [ includes ] -------------------------------------------
//
#include "Test.h"
#include <new>
 
// --- [ prototypes ] -----------------------------------------
//
template<class T>
void CallDestructor( T* inObject );
 
template<class T>
void CallDestructor( T** inObject );
 
// --- [ entry point ] ----------------------------------------
//
void main()
{
	char buffer[2048];
 
	// Case 1: Single New
	{
		// Create Class
		Test * pClass = new ( buffer ) Test();
 
		// Call class destructor
		CallDestructor( pClass );
	}
 
	// Case 2: Single New Array of Pointers
	{
		// Create Pointer List
		Test ** pClassList = new ( buffer ) Test*[10];
 
		// Call destructor
		CallDestructor( pClassList );
	}
}
 
// --- [ functions ] ------------------------------------------
//
template<class T>
void CallDestructor( T* inObject )
{
	inObject->~T();
}
 
template<class T>
void CallDestructor( T** inObject )
{
	// Do nothing
}

 

Those both work fine, however the problem arises when you allocate an array of objects as below.

// --- [ includes ] -------------------------------------------
//
#include "Test.h"
#include <new>
 
// --- [ prototypes ] -----------------------------------------
//
template<class T>
void CallDestructor( T* inObject );
 
template<class T>
void CallDestructor( T** inObject );
 
// --- [ entry point ] ----------------------------------------
//
int main()
{
	char buffer[2048];
 
	// Case 1: Single New
	{
		// Create Class
		Test * pClass = new ( buffer ) Test();
 
		// Call class destructor
		CallDestructor( pClass );
	}
 
	// Case 2: Single New Array of Pointers
	{
		// Create Pointer List
		Test ** pClassList = new ( buffer ) Test*[10];
 
		// Call destructor
		CallDestructor( pClassList );
	}
 
	// Case 3: Multiple Object New in Array
	{
		// Create Array of Objects
		Test * pClassArray = new ( buffer ) Test[10];
 
		// Call destructor
		CallDestructor( pClassArray );
	}
 
	return 0;
}
 
// --- [ functions ] ------------------------------------------
//
template<class T>
void CallDestructor( T* inObject )
{
	inObject->~T();
}
 
template<class T>
void CallDestructor( T** inObject )
{
// Do nothing
}

 

If you debug through this code you’ll notice that case 1 and 2 still work, however when you get to case 3, the destructor is only called once, since it cannot tell the difference between an array and a single class that was allocated with new.

I can only think of three ways around this at the moment.

  1. Store the Number of Objects in this array and manually iterate through free them
  2. Override the placement new operator with my own that adds a header to the memory block that stores the number of elements so it can be retrieved to iterate through.
  3. Override the default delete operator, this way the delete operator can be used as you normally would to free objects created with new.

The last option seems to the best one, however overriding both default delete operators would mean I’d need my own memory management system, and override the default new operators as well.

Best get to work on that…