- Overview
-
Table of Contents
- Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Operator Overloading
- Memory Management
- Templates
- Namespaces
- Time and Date Library
- Streams
- Object-Oriented Programming and Design Principles
- The Standard Template Library (STL) and Generic Programming
- Exception Handling
- Runtime Type Information (RTTI)
- Signal Processing
- Creating Persistent Objects
- Bit Fields
- New Cast Operators
- Environment Variables
- Variadic Functions
- Pointers to Functions
- Function Objects
- Pointers to Members
- Lock Files
- Design Patterns
- Dynamic Linking
-
Tips and Techniques
- Using the Swap() Algorithm
- Using class stopwatch for Performance Measurements
- Extending <tt><iostream></tt> to Support User-Defined Types
- Using <tt>auto_ptr</tt> To Automate Memory Management
- Using <tt>auto_ptr</tt> To Automate Memory Management, Part II
- Using <tt>auto_ptr</tt> To Automate Memory Management, Part III
- Using <tt>enum</tt>s as Mnemonic Indexes
- Create Objects on Pre-Allocated Memory Using <tt>Placement-new</tt>
- Online Books: <tt>Placement-new</tt>
- Bitwise Operators
- Bitwise Operators II
- Who's <tt>this</tt>?
- A Reference Guide
- The Virtues of Multiple Inheritance
- Interfaces
- Multiple Inheritance: Construction and Destruction Order
- nothrow new
- POD Initialization
- Object Initialization
- <tt>const</tt> Declarations
- The Semantics of <tt>volatile</tt>
- <tt>inline</tt> Functions
- Project Organization Guidelines
- All About <tt>bool</tt>
- <tt>typedef</tt> Declarations
- State of the <tt>union</tt>
- Dynamic Cast Uses
- Integrating C and C++
- <tt>const</tt>-Correctness
- <tt>const</tt>-Correctness: Advanced Issues
- Sprucing Up Legacy Code
- Virtual Constructors
- Naming Names
- Function Calls
- Speaking Standardese (updated)
- Speaking Standardese: the One Definition Rule
- Declarations and Definitions
- More on Declarations and Definitions
- The Most Vexing Parse
- Finally, At Last
- Sound Bytes (Admittedly Off Topic)
- Local Classes
- Complex Arithmetic
- Floating Point Woes
- String Manipulation
- The Object Model
- The Object Model II
- The Object Model III
- Temporary Objects
- Temporary Objects: Advanced Techniques
- Over-Engineering
- Security Enhancements
- Drop the (automatic) Pilot
- Choosing the Right Container
- Choosing the Right Container II
- Choosing the Right Container, Part III
- Arrays and Pointers
- Low-Level File I/O
- Low-Level File I/O Part II
- static Declarations, Part I
- static Declarations, Part II
- <code>static</code> Initialization Order
- Revisiting the Deprecation of File-Scope Static
- Virtual Memory and Memory Mapping
- Cellular Phone Programming Guidelines
- The Handle/Body Idiom
- Whole Program Optimization, Part I
- Whole Program Optimization, Part II
- Manipulating Directories
- Window Dressing
- <code>friend</code> Declarations
- <code>friend</code> Part II: the Interaction of Friendship and Template Classes
- Forcing Object Allocation on Specific Storage Types
- Lazy Evaluation
- Cache and Carry
- Controlling a Container’s Capacity
- Non-Blocking I/O, Part I
- Non-Blocking I/O, Part II
- Using Unions for Automatic Conversion
- Launching a Child Process
- <tt>switch</tt> Statements
- Introducing the "struct Hack"
- Scoped Enumerators
- Doing Statistics with STL
- Fixing the "Unresolved External" Linkage Error
- Understanding Calling Conventions
- Understanding the Empty Base Optimization
- Implementing RPC with the door Library, Part 1
- Implementing RPC with the door Library, Part 2
- Eliminating Two Common Pointer and <tt>sizeof</tt> Bugs
- Command Line Arguments
- Performance Myths Busting
- Tag Names And Types Part I
- Tag Names And Types Part II
- The Infamous goto
- Trimming Strings
- Can Objects Live Forever? Part I
- Can Objects Live Forever? Part II
- Five Ways to Improve Your Functions
- Member Aggregate Initialization
- Five Futile Coding-Style Debates
- The Good Parasite Idiom: An Exercise in OOD
- The Good Parasite Idiom: An Exercise in OOD, Part II
- The Good Parasite Idiom: An Exercise in OOD, Part III
- Ten Techniques to Reduce the Size of Your Classes, Part I
- Ten Techniques to Reduce the Size of Your Classes, Part II: Inheritance Issues
- Ten Techniques to Reduce the Size of Your Classes, Part III
- Ten Techniques to Reduce the Size of Your Classes IV
- Taking the Address of an Object with an Overloaded Operator <tt>&</tt>
- strcpy() -- How and Why Does It "Just Work"?
- Anonymous Structs
- Five Easy Ways to Reduce The Size of your Executables
- Standard Layout Classes and Trivially Copyable Types, Part I
- Standard Layout Classes and Trivially Copyable Types, Part II
- Five Simple Code Sanity Checks
- Five Things You Need to Know About C++11 Unions
- A Tour of C99
- A Tour of C1X
- C++0X: The New Face of Standard C++
- C++0x Concurrency
- The Reflecting Circle
- We Have Mail
- The Soapbox
- Numeric Types and Arithmetic
- Careers
- Locales and Internationalization
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[].
