Content deleted Content added
Scott Bowden (talk | contribs) No edit summary |
Rewrote. |
||
Line 1:
{{lowercase|title=Placement new (C++)}}
In the [[C++]] [[programming language]], '''placement syntax''' allows programmers to explicitly specify the [[memory management]] of individual objects — i.e. their "placement" in [[memory (computing)|memory]]. The "placement" versions of the <code>new</code> and <code>delete</code> operators and functions are known as '''placement <code>new</code>''' and '''placement <code>delete</code>'''.<ref name=McCluskey1>{{cite web|url=http://glenmccl.com./nd_cmp.htm|title=Placement New/Delete|publisher=Glen McCluskey & Associates LLC|work=C++ Language and Library|date=[[2000-06-26]]}}</ref>
A new ''expression'', placement or otherwise, calls an new ''function'', also known as an allocator function, whose name is <code>operator new</code>. Similarly, a delete ''expression'' calls a delete ''function'', also known as a deallocator function, whose name is <code>operator new</code>.<ref name=Lischner1 /><ref name=Lippman1 />
== Expressions ==
The Standard C++ syntax for a non-placement <code>new</code> expression is<ref name=Lischner1>{{cite book|title=C++ in a Nutshell|author=Ray Lischner|pages=72–73,128–129,310,623–625|publisher=O'Reilly|date=2003|isbn=059600298X|isbn13=9780596002985}}</ref>
:<code>new</code> ''new-type-id'' ( ''optional-initializer-expression-list'' )</code>
The placement syntax adds an expression list immediately after the <code>new</code> keyword. This expression list is the placement.<ref name=Lischner1 /><ref name=Lippman1>{{cite book|title=C++ Gems|author=Stanley B. Lippman|pages=386–389|publisher=Cambridge University Press|date=1997|isbn=0135705819|isbn13=9780135705810}}</ref>
:<code>new</code> ( ''expression-list'' ) ''new-type-id'' ( ''optional-initializer-expression-list'' )</code>
There is no placement delete expression.<ref name=SolterKleper>{{cite book|title=Professional C++|author=Nicholas Solter and Scott Kleper|pages=458–461|publisher=Wiley|date=2005|isbn=0764574841|isbn13=9780764574849}}</ref>
=== Compiler quirks ===
Versions of the [[g++]] compiler prior to version 2.3.1 accept a different syntax for placement new expressions:<ref name=Buck1>{{cite web|url=http://desy.de./user/projects/C++/g++faq/placement_new_syntax.html|title=3.4. g++ won't accept the placement new syntax.|date=[[1997-05-12]]|author=Joe Buck|work=Frequently asked questions about the GNU C++ compiler|accessdate=[[2008-11-26]]}}</ref>
:<code>new</code> { ''expression-list'' } ''new-type-id'' ( ''optional-initializer-expression-list'' )</code>
Up until version 2.2.2, this was the ''only'' placement syntax that that compiler would accept.<ref name=Buck1 />
== 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 <code>new</code> expressions respectively, are:<ref name=Vermeir1>{{cite book|title=Multi-paradigm Programming Using C++|author=Dirk Vermeir|pages=113–115|publisher=Springer|date=2001|isbn=1852334835|isbn13=9781852334833}}</ref><ref name=TCPPPL>{{cite book|last=Stroustrup|first=Bjarne|author-link=Bjarne Stroustrup|title=The C++ Programming Language|publisher=[[Addison-Wesley]]|edition=third|isbn=9780201889543|year=1997|pages=255–256,576}}</ref>
:<source lang="cpp" enclose=div>
void * operator new (size_t) throw(std::bad_alloc);
void * operator new[] (size_t) throw(std::bad_alloc);
</source>
The Standard C++ library provides two placement overloads each for these functions. Their declarations are:<ref name=Vermeir1 /><ref name=TCPPPL />
:<source lang="cpp"
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();
</source>
In all of the overloads, the first parameter to the <code>operator new</code> function is of type <source lang="cpp" enclose=none>size_t</source>, 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 <source lang="cpp" enclose=none>void *</source>, which is a [[pointer (computing)|pointer]] to the storage that the function allocates.<ref name=Lischner1 />
There are also placement delete functions. They are overloaded versions of the non-placement delete functions. The non-placement delete functions are declared as:<ref name=Vermeir1 /><ref name=TCPPPL />
:<source lang="cpp" enclose=div>
void operator delete (void *) throw();
void operator delete[] (void *) throw();
</source>
The Standard C++ library provides two placement overloads each for these functions. Their declarations are:<ref name=Vermeir1 /><ref name=TCPPPL />
:<source lang="cpp" enclose=div>
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();
</source>
In all of the overloads, the first parameter to the <code>operator delete</code> function is of type <source lang="cpp" enclose=none>void *</source>, which is the address of the storage to deallocate.<ref name=Lischner1 />
For both the new and the delete functions, the functions are global, are not in any namespace, and do not have static linkage.<ref name=Lischner1 />
== Use ==
Placement syntax has four main uses: default placement, preventing exceptions, custom allocators, and debugging.
=== Default placement ===
The placement overloads of <code>operator new</code> and <code>operator delete</code> that employ an additional <source lang="cpp" enclose=none>void *</source> 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:<ref name=Vermeir1 /><ref name=TCPPPL /><ref name=Anderson1>{{cite book|title=Navigating C++ and Object-oriented Design|author=Gail Anderson|chapter=Object Storage Management|pages=345–356|publisher=Prentice Hall|date=1998|isbn=0135327482|isbn13=9780135327487}}</ref>
:<source lang="cpp" enclose=div>
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() { }
</source>
Default placement does not require the inclusion of the Standard C++ library header <code><new></code> in the source code of a C++ program.<ref name=Lischner1 />
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.<ref name=DAEOC>{{cite book|last=Stroustrup|first=Bjarne|author-link=Bjarne Stroustrup|title=Design and Evolution of C++|publisher=[[Addison-Wesley]]|isbn=9780201543308|year=1994|chapter=Memory Management}}</ref>
Other uses, however, include calling a constructor directly, something which the C++ language does not otherwise permit.<ref name=Lippman1 />
=== Preventing exceptions ===
Normally, the (non-placement) new functions throw an exception, of type <code>std::bad_alloc</code>, 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 <source lang="cpp" enclose=none>NULL</source> pointer when an error occurred, is accessible via placement syntax.<ref name=Lippman1 />
Programmers that wish to do this in their programs must include the Standard C++ library header <code><new></code> in the source code. This header defines the global <code>std::nothrow</code> object, which is of type <code>std::nothrow_t</code> (also defined in the header), which is used to call the overloaded new functions that are declared as taking <source lang="cpp" enclose=none>const nothrow_t &</source> as their second parameter. For example:<ref name=Anderson1 />
:<source lang="cpp" enclose=div>
#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 ;
}
</source>
=== Custom allocators ===
{{sect-stub}}
=== 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 <code><new></code>, bu does require the inclusion of a header that defines four placement functions and a macro replacement for the <code>new</code> keyword that is used in new expressions. For example, such a header would contain:<ref name=Anderson1 /><ref name=Yongwei1>{{cite web|title=A Cross-Platform Memory Leak Detector|date=[[2007-12-31]]|author=Wu Yongwei|accessdate=[[2008-11-26]]|work=Wu Yongwei's Programming Page|url=http://wyw.dcweb.cn/leakage.htm}}</ref>
:<source lang="cpp" enclose=div>
#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
</source>
This would be employed in a program as follows:<ref name=Anderson1 /><ref name=Yongwei1 />
:<source lang="cpp" enclose=div>
T * p = New T ;
</source>
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:<ref name=Anderson1 /><ref name=Yongwei1 />
:<source lang="cpp" enclose=div>
#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) ;
}
</source>
== Placement delete ==
As noted above, there is no placement delete expression. It is not possible to call ''any'' placement <code>operator delete</code> function using a <code>delete</code> expression.<ref name=SolterKleper />
The placement delete functions are called from placement <code>new</code> expressions. In particular, they are called if the [[constructor (computer science)|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 <code>operator new</code> 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.<ref name=SolterKleper />
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 <code>operator delete(void *, const A &)</code>:<ref name=SolterKleper />
:<source lang="cpp" enclose=div>
#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 ;
}
</source>
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.<ref name=SolterKleper />
==References==
<references/>
==Further reading==
* {{cite book|last=Franek|first=Frantisek|title=Memory as a Programming Concept in C and C++|publisher=[[Cambridge University Press]]|isbn=9780521520430|year=2004}}
* [http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=/com.ibm.vacpp6m.doc/language/ref/clrc05cplr199.htm IBM Documentation describing C++'s operator new]
* [http://msdn2.microsoft.com/en-us/library/kewsb8ba(VS.71).aspx Microsoft Visual Studio operator new documentation]
* [http://www.devx.com/tips/Tip/12582 Tip of the day for July 18, 1998]
==See also==
* <code>[[new (C++)|new]]</code>
[[Category:C++]]
|