In the C++ programming language, placement syntax allows programmers to explicitly specify the memory management of individual objects — i.e. their "placement" in memory. The "placement" versions of the new
and delete
operators and functions are known as placement new
and placement delete
.[1]
A new expression, placement or otherwise, calls an new function, also known as an allocator function, whose name is operator new
. Similarly, a delete expression calls a delete function, also known as a deallocator function, whose name is operator new
.[2][3]
Expressions
The Standard C++ syntax for a non-placement new
expression is[2]
new
new-type-id ( optional-initializer-expression-list )
The placement syntax adds an expression list immediately after the new
keyword. This expression list is the placement.[2][3]
new
( expression-list ) new-type-id ( optional-initializer-expression-list )
There is no placement delete expression.[4]
Compiler quirks
Versions of the g++ compiler prior to version 2.3.1 accept a different syntax for placement new expressions:[5]
new
{ expression-list } new-type-id ( optional-initializer-expression-list )
Up until version 2.2.2, this was the only placement syntax that that compiler would accept.[5]
Functions
The placement new functions are overloads of the non-placement new functions. The declaration of the non-placement new functions, for non-array and array new
expressions respectively, are:[6][7]
void * operator new (size_t) throw(std::bad_alloc); void * operator new[] (size_t) throw(std::bad_alloc);
The Standard C++ library provides two placement overloads each for these functions. Their declarations are:[6][7]
void * operator new (size_t, const std::nothrow_t &) throw(); void * operator new (size_t, void *) throw(); void * operator new[] (size_t, const std::nothrow_t &) throw(); void * operator new[] (size_t, void *) throw();
In all of the overloads, the first parameter to the operator new
function is of type size_t
, which when the function is called will be passed as an argument the amount of memory, in bytes, to allocate. All of the functions must return type void *
, which is a pointer to the storage that the function allocates.[2]
There are also placement delete functions. They are overloaded versions of the non-placement delete functions. The non-placement delete functions are declared as:[6][7]
void operator delete (void *) throw(); void operator delete[] (void *) throw();
The Standard C++ library provides two placement overloads each for these functions. Their declarations are:[6][7]
void operator delete (void *, const std::nothrow_t &) throw(); void operator delete (void *, void *) throw(); void operator delete[] (void *, const std::nothrow_t &) throw(); void operator delete[] (void *, void *) throw();
In all of the overloads, the first parameter to the operator delete
function is of type void *
, which is the address of the storage to deallocate.[2]
For both the new and the delete functions, the functions are global, are not in any namespace, and do not have static linkage.[2]
Use
Placement syntax has four main uses: default placement, preventing exceptions, custom allocators, and debugging.
Default placement
The placement overloads of operator new
and operator delete
that employ an additional void *
parameter are used for default placement, also known as pointer placement. Their definitions by the Standard C++ library, which it is not permitted for a C++ program to replace or override, are:[6][7][8]
void * operator new (size_t, void * p) throw() { return p ; } void * operator new[] (size_t, void * p) throw() { return p ; } void operator delete (void *, void *) throw() { } void operator delete[] (void *, void *) throw() { }
Default placement does not require the inclusion of the Standard C++ library header <new>
in the source code of a C++ program.[2]
There are various uses for default placement.
Bjarne Stroustrup originally observed, in his book The Design and Evolution of C++, that pointer placement new is necessary for hardware that expects a certain object at a specific hardware address. It is also required for the construction of objects that need to reside in a certain memory area, such as an area that is shared between several processors of a multiprocessor computer.[9]
Other uses, however, include calling a constructor directly, something which the C++ language does not otherwise permit.[3]
Preventing exceptions
Normally, the (non-placement) new functions throw an exception, of type std::bad_alloc
, if they encounter an error, such as exhaustion of all available memory. This was not how the functions were defined by Stroustrup's Annotated C++ Reference Manual, but was a change made by the standardization committee when the C++ language was standardized. The original behaviour of the functions, which was to return a NULL
pointer when an error occurred, is accessible via placement syntax.[3]
Programmers that wish to do this in their programs must include the Standard C++ library header <new>
in the source code. This header defines the global std::nothrow
object, which is of type std::nothrow_t
(also defined in the header), which is used to call the overloaded new functions that are declared as taking const nothrow_t &
as their second parameter. For example:[8]
#include <new> struct T {} ; int main () { // Call the function operator new(size_t, const nothrow_t &) and (if successful) construct the object. T * p = new (std::nothrow) T ; if (p) { // The storage has been allocated and the constructor called. delete p ; } else ; // An error has occurred. No storage has been allocated and no object constructed. return 0 ; }
Custom allocators
This section needs expansion. You can help by adding to it. |
Debugging
Placement new can also be used as a simple debugging tool, to enable programs to print the filename and line number of the source code where a memory allocation has failed. This does not require the inclusion of the Standard C++ library header <new>
, bu does require the inclusion of a header that defines four placement functions and a macro replacement for the new
keyword that is used in new expressions. For example, such a header would contain:[8][10]
#if defined(DEBUG_NEW) void * operator new (size_t size, const char* file, int line); void * operator new[] (size_t size, const char* file, int line); void operator delete (void * p, const char* file, int line); void operator delete[] (void * p, const char* file, int line); #define New new(__FILE__, __LINE__) #else #define New new #endif
This would be employed in a program as follows:[8][10]
T * p = New T ;
The custom-written placement new functions would then handle using the supplied file and line number information in the event of an exception. For example:[8][10]
#include <new> #include <cstdlib> class NewError { public: NewError(const char * file, int line) { /* ... */ } /* ... */ } ; void * operator new (size_t size, const char* file, int line) { if (void * p = ::operator new (size, std::nothrow)) return p ; throw NewError(file, line) ; }
Placement delete
As noted above, there is no placement delete expression. It is not possible to call any placement operator delete
function using a delete
expression.[4]
The placement delete functions are called from placement new
expressions. In particular, they are called if the constructor of the object throws an exception. In such a circumstance, in order to ensure that the program does not incur a memory leak, the placement delete functions are called. A placement new expression first calls the placement operator new
function, then calls the constructor of the object upon the raw storage returned from the allocator function. If the constructor throws an exception, it is necessary to deallocate that storage before propagating the exception back to the code that executed the placement new expression, and that is the purpose of the placement delete functions.[4]
The placement delete function that is called matches the placement new function that was invoked by the placement new expression. So, for example, if the following code is executed, the placement delete function that is called will be operator delete(void *, const A &)
:[4]
#include <cstdlib> struct A {} ; struct E {} ; class T { public: T() { throw E() ; } } ; void * operator new ( size_t, const A & ) ; void operator delete ( void *, const A & ) ; int main () { A a ; T * p = new (a) T ; return 0 ; }
This is why the pointer placement delete functions are defined as no-operations by the Standard C++ library. Since the pointer placement new functions do not allocate any storage, there is no storage to be deallocated in the event of the object's constructor throwing an exception.[4]
References
- ^ "Placement New/Delete". C++ Language and Library. Glen McCluskey & Associates LLC. 2000-06-26. Retrieved 2008-11-26.
{{cite web}}
: Check date values in:|accessdate=
and|date=
(help) - ^ a b c d e f g Ray Lischner (2003). C++ in a Nutshell. O'Reilly. pp. 72–73, 128–129, 310, 623–625. ISBN 059600298X.
{{cite book}}
: Unknown parameter|isbn13=
ignored (help) - ^ a b c d Stanley B. Lippman (1997). C++ Gems. Cambridge University Press. pp. 386–389. ISBN 0135705819.
{{cite book}}
: Unknown parameter|isbn13=
ignored (help) - ^ a b c d e Nicholas Solter and Scott Kleper (2005). Professional C++. Wiley. pp. 458–461. ISBN 0764574841.
{{cite book}}
: Unknown parameter|isbn13=
ignored (help) - ^ a b Joe Buck (1997-05-12). "3.4. g++ won't accept the placement new syntax". Frequently asked questions about the GNU C++ compiler. Retrieved 2008-11-26.
{{cite web}}
: Check date values in:|accessdate=
and|date=
(help) - ^ a b c d e Dirk Vermeir (2001). Multi-paradigm Programming Using C++. Springer. pp. 113–115. ISBN 1852334835.
{{cite book}}
: Unknown parameter|isbn13=
ignored (help) - ^ a b c d e Stroustrup, Bjarne (1997). The C++ Programming Language (third ed.). Addison-Wesley. pp. 255–256, 576. ISBN 9780201889543.
- ^ a b c d e Gail Anderson (1998). "Object Storage Management". Navigating C++ and Object-oriented Design. Prentice Hall. pp. 345–356. ISBN 0135327482.
{{cite book}}
: Unknown parameter|isbn13=
ignored (help) - ^ Stroustrup, Bjarne (1994). "Memory Management". Design and Evolution of C++. Addison-Wesley. ISBN 9780201543308.
- ^ a b c Wu Yongwei (2007-12-31). "A Cross-Platform Memory Leak Detector". Wu Yongwei's Programming Page. Retrieved 2008-11-26.
{{cite web}}
: Check date values in:|accessdate=
and|date=
(help)
Further reading
- Franek, Frantisek (2004). Memory as a Programming Concept in C and C++. Cambridge University Press. ISBN 9780521520430.
- IBM Documentation describing C++'s operator new
- Microsoft Visual Studio operator new documentation
- Tip of the day for July 18, 1998