Placement syntax: Difference between revisions

Content deleted Content added
History: grammar
No edit summary
Line 17:
== 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=Vermeir2001 /><ref name=Stroustrup1997b /><syntaxhighlight lang="cpp">
void * operator new (std::size_t) throw(std::bad_alloc);
void * operator new[] (std::size_t) throw(std::bad_alloc);
</syntaxhighlight>
 
The Standard C++ library provides two placement overloads each for these functions. Their declarations are:<ref name=Vermeir2001 /><ref name=Stroustrup1997b /><syntaxhighlight lang="cpp">
void * operator new (std::size_t, const std::nothrow_t &) throw();
void * operator new (std::size_t, void *) throw();
void * operator new[] (std::size_t, const std::nothrow_t &) throw();
void * operator new[] (std::size_t, void *) throw();
</syntaxhighlight>
 
Line 31:
 
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=Vermeir2001 /><ref name=Stroustrup1997b /><syntaxhighlight lang="cpp">
void operator delete (void *) throw();
void operator delete[] (void *) throw();
</syntaxhighlight>
 
The Standard C++ library provides two placement overloads each for these functions. Their declarations are:<ref name=Vermeir2001 /><ref name=Stroustrup1997b /><syntaxhighlight lang="cpp">
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();
</syntaxhighlight>
 
Line 51:
=== Default placement ===
The placement overloads of <code>operator new</code> and <code>operator delete</code> that employ an additional <syntaxhighlight lang="cpp" inline>void *</syntaxhighlight> 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=Vermeir2001 /><ref name=Stroustrup1997b /><ref name=Anderson1998a /><syntaxhighlight lang="cpp">
void * operator new (std::size_t, void * p) throw() { return p ; }
void * operator new[] (std::size_t, void * p) throw() { return p ; }
void operator delete (void *, void *) throw() { }
void operator delete[] (void *, void *) throw() { }
</syntaxhighlight>
 
Line 65:
The C++ language does allow a program to call a [[destructor (computer science)|destructor]] directly, and, since it is not possible to destroy the object using a <code>delete</code> expression, that is how one destroys an object that was constructed via a pointer placement new expression. For example:<ref name=SolterKleper2005 /><ref name=SeedCooper2001 />
: <syntaxhighlight lang="cpp">
p->~T() ;
</syntaxhighlight>
 
Line 78:
This operator is implemented as:<syntaxhighlight lang="cpp">
 
inline void* operator new( std::size_t szcount, void* here ) { return here; }
void* operator new[](std::size_t count, void* here) { return here ; }
inline void* operator new[]( size_t sz, void* here )
{ return here ; }
</syntaxhighlight>
 
Line 90 ⟶ 88:
#include <new>
 
struct T {} ;
 
int main () {
{
// Call the function operator new(std::size_t, const std::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 ;
}
</syntaxhighlight>
Line 110 ⟶ 107:
class A {
public:
void * allocate ( std::size_t ) ;
void deallocate ( void * ) ;
} ;
</syntaxhighlight>
 
And define custom placement allocation and deallocation functions as follows:<ref name=Vermeir2001 /><ref name=Stroustrup1997b /><syntaxhighlight lang="cpp">
inline void* operator new[]( std::size_t szsize, void*A& herearena) ){
void *
return arena.allocate(size) ;
operator new (std::size_t size, A & arena)
{
return arena.allocate(size) ;
}
 
void
void operator delete (void * p, A & arena) {
arena.deallocate(p) ;
{
arena.deallocate(p) ;
}
</syntaxhighlight>
 
The program would employ the placement syntax to allocate objects using different instances of the <code>A</code> class as follows:<ref name=Vermeir2001 /><ref name=Stroustrup1997b /><syntaxhighlight lang="cpp">
A first_arena, second_arena ;
T * p1 = new (first_arena) T ;
T * p2 = new (second_arena) T ;
</syntaxhighlight>
 
Line 137 ⟶ 131:
 
The former would resemble:<ref name=Stroustrup1997b /><syntaxhighlight lang="cpp">
void destroy (T * p, A & arena) {
void
p->~T() ; // First invoke the destructor explicitly.
destroy (T * p, A & arena)
arena.deallocate(p) ; // Then call the deallocator function directly.
{
p->~T() ; // First invoke the destructor explicitly.
arena.deallocate(p) ; // Then call the deallocator function directly.
}
</syntaxhighlight>
which would be invoked from a program as:<syntaxhighlight lang="cpp">
A arena ;
T * p = new (arena) T ;
/* ... */
destroy(p, arena) ;
</syntaxhighlight>
 
The latter would involve simply writing the destructor invocation and delete function call into the program:<ref name=Vermeir2001 /><ref name=Dewhurst2003 /><syntaxhighlight lang="cpp">
A arena ;
T * p = new (arena) T ;
/* ... */
p->~T() ; // First invoke the destructor explicitly.
operator delete(p, arena) ; // Then call the deallocator function indirectly via operator delete(void *, A &) .
</syntaxhighlight>
 
Line 164 ⟶ 156:
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>&lt;new&gt;</code>, but does require the inclusion of a header that declares 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=Anderson1998a /><ref name=Yongwei2007 /><syntaxhighlight lang="cpp">
#if defined(DEBUG_NEW)
void * operator new (std::size_t size, const char* file, int line);
void * operator new[] (std::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
Line 175 ⟶ 167:
 
This would be employed in a program as follows:<ref name=Anderson1998a /><ref name=Yongwei2007 /><syntaxhighlight lang="cpp">
T * p = New T ;
</syntaxhighlight>
 
Line 184 ⟶ 176:
class NewError {
public:
NewError(const char * file, int line) { /* ... */ }
/* ... */
} ;
 
void *
operator new (std::size_t size, const char* file, int line)
{
if (void * p = ::operator new (size, std::nothrow))
return p ;
throw NewError(file, line) ;
}
</syntaxhighlight>
Line 206 ⟶ 198:
#include <iostream>
 
struct A {} ;
struct E {} ;
 
class T {
public:
T() { throw E() ; }
} ;
 
void * operator new ( std::size_t, const A &) ){
{std::cout << "Placement new called." << std::endl;
}
void operator delete ( void *, const A & )
{std::cout << "Placement delete called." << std::endl;}
 
void operator delete ( void *, const A &) ){
int main ()
{std::cout << "Placement delete called." << std::endl;}
{
A a ;
try {
T * p = new (a) T ;
} catch (E exp) {std::cout << "Exception caught." << std::endl;}
return 0 ;
}
 
int main (){
A a ;
try {
T * p = new (a) T ;
} catch (E exp) {
} catch (E exp) {std::cout << "Exception caught." << std::endl;}
}
{ return here 0; }
}
</syntaxhighlight>