Home > Articles > Programming > C/C++

C++ Reference Guide

Hosted by

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

Create Objects on Pre-Allocated Memory Using <tt>Placement-new</tt>

Last updated Jan 1, 2003.

Constructing objects on a predetermined memory location is useful in real-time and embedded programming, system programming and other application domains. I will show you how to accomplish this task by using placement new and other built-in C++ constructs that were particularly designed for this purpose.

Allocation Strategies

The most common forms of new are scalar new and array new as shown in the following example:

string * s = new string;
char *line = new char[81];

These versions of new (to which I will refer as ordinary new henceforth) allocate storage from the free-store at runtime. For most purposes, this allocation policy is plausible and rather efficient.

In certain applications, however, determinacy is paramount. Not only must the program ensure that object allocation succeeds, but the allocation should be completed within a predictable amount of time.

Pre-allocating a large chunk of memory in advance and using it during the application's lifetime is a common strategy. To facilitate this task, C++ defines a special version of operator new called placement new.

Using Placement-new

Unlike ordinary new, placement new takes an additional argument: the memory address on which the object will be constructed. Since placement new doesn't really allocate storage, it's faster and safer than ordinary new. Of course, the programmer must guarantee that the pre-allocated storage is sufficiently large and that it meets the system's alignment requirements.

To meet these criteria, use ordinary new to allocate raw storage. Then use placement new to construct the desired object on the previously allocated storage. Let's look at a concrete example.

Suppose you have the following class:

class Timer
{
public:
 int sleep(long msec);
 int reset();
 Timer(char * name="");
 ~Timer();
//...
private:
 int timer_id;
 int thread_id; 
//...
};

You're developing an application that uses a timer to invoke a screensaver after 10 minutes of inactivity. This application must run for weeks and even months uninterruptedly. Repeatedly allocating objects using ordinary new is ruled out because it might fragment the heap until the application crashes. Instead, you decide to pre-allocate sufficient storage from the free-store at the program's startup and then recycle it to construct new objects as needed. Your first step is to pre-allocate raw storage like this:

char * raw_mem = new char [sizeof (Timer)];

C++ guarantees that the memory returned from new meets the strictest alignment requirements for every type of object. Therefore, you can use a dynamically allocated char array as the basis for constructing any other type of object. However, don't be tempted to use stack memory for this purpose:

char * buff [sizeof (Timer)]; //bad idea

A char array allocated in this way might not be properly aligned for objects of any other type but char.

Next, construct an object on the pre-allocated storage it like this (remember to #include the standard header <new> when using placement new):

#include <new>
Timer * ptimer = new (raw_mem) Timer; // #1

In the statement numbered #1, placement new constructs a Timer object on raw_mem and returns its address. The argument raw_mem is enclosed between a pair of parentheses after the keyword new. It's the address on which the object will be constructed. Placement new is -safe; unlike ordinary new, it doesn't throw. You can now use ptimer:

ptimer->sleep(60000*15); //sleep for 15 minutes

Explicit Destructor Invocation

Objects allocated by placement new require an explicit destructor invocation once they aren't needed. Don't use delete or delete[] to destroy them as this would cause undefined behavior:

delete ptimer; // bad idea

The problem is that delete knows which object new allocated originally, namely a char array. It doesn't know that a different object was later constructed on that array. Therefore, it won't invoke Timer's destructor. Worse yet, because the original buffer was allocated using new[], you must use delete[] to release it. Here's how you invoke Timer's destructor:

ptimer->~Timer(); //explicit destructor invocation

At this point, you may recycle raw_mem and construct a new object on it:

Timer * ptimer2 = new (raw_mem) Timer("2nd timer");
ptimer2->sleep(60000); //sleep for 1 minutes

You may repeat the construction and destruction steps indefinitely. This way, you avoid both the memory fragmentation incurred by dynamic allocations and ensure determinacy.

Cleanup

An explicit destructor invocation only destroys the Timer object. To release raw_mem, you still need to use delete[] thereafter:

delete[] raw_mem;

Summary

Placement new is a powerful but dangerous feature. Although the example shown here uses a simple class, in real world applications you would use it to allocate large objects, such as images and files. Note also that while placement new doesn't support arrays, you can easily build multiple objects on the same preallocated storage by calculating the offset of each object.

When using placement new, follow these guidelines to prevent bugs, memory leaks and inefficiencies:

  • Preallocate storage using new to meet the strictest alignment requirements.

  • Use sizeof() to determine the size of the object to be allocated.

  • Invoke the object's destructor explicitly when it's no longer needed. You may then recycle the raw storage to construct more objects.

  • Before the program terminates, remember to release the storage by calling delete[].