Placement syntax: Difference between revisions

Content deleted Content added
Add category
Citation bot (talk | contribs)
Removed URL that duplicated identifier. | Use this bot. Report bugs. | Suggested by Headbomb | Linked from Wikipedia:WikiProject_Academic_Journals/Journals_cited_by_Wikipedia/Sandbox | #UCB_webform_linked 104/967
 
(6 intermediate revisions by 5 users not shown)
Line 3:
The "placement" versions of the <code>[[new (C++)|new]]</code> and <code>[[delete (C++)|delete]]</code> operators and functions are known as placement <code>new</code> and placement <code>delete</code>.<ref name=McCluskey2000 /> A <code>new</code> ''expression'', placement or otherwise, calls a <code>new</code> ''function'', also known as an allocator function, whose name is <code>operator new</code>. Similarly, a <code>delete</code> ''expression'' calls a <code>delete</code> ''function'', also known as a deallocator function, whose name is <code>operator delete</code>.<ref name=Lischner2003 /><ref name=Lippman1997 />
 
Any <code>new</code> expression that uses the placement syntax is a placement <code>new</code> expression, and any <code>operator new</code> or <code>operator delete</code> function that takes more than the mandatory first parameter (<syntaxhighlight lang="cpp" inline>std::size_t</syntaxhighlight>) is a placement new or placement delete function.<ref name=Meyers1998 /> A placement new function takes two input parameters: <syntaxhighlight lang="cpp" inline>std::size_t</syntaxhighlight> and <syntaxhighlight lang="cpp" inline>void *</syntaxhighlight>.
 
== History ==
In earlier versions of C++, there was no such thing as ''placement new''; instead, developers used explicit assignment to ''<code>this''</code> within constructors to achieve similar effect.<ref name=Stroustrup1991 /> This practice has been deprecated and abolished later,{{When|date=April 2025 |reason=Is there a specific C++ standard that abolishes this technique?}} and the third edition of ''[[The C++ Programming Language]]'' doesn'tdoes not mention this technique.
 
== Expressions ==
Line 18:
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()noexcept;
void* operator new(std::size_t, void*) throw()noexcept;
void* operator new[](std::size_t, const std::nothrow_t&) throw()noexcept;
void* operator new[](std::size_t, void*) throw()noexcept;
</syntaxhighlight>
 
In all of the overloads, the first parameter to the <code>operator new</code> function is of type <syntaxhighlight lang="cpp" inline>std::size_t</syntaxhighlight>, which when the function is called will be passed as an argument specifying the amount of memory, in bytes, to allocate. All of the functions must return type <syntaxhighlight lang="cpp" inline>void *</syntaxhighlight>, which is a [[pointer (computer programming)|pointer]] to the storage that the function allocates.<ref name=Lischner2003 />
 
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()noexcept;
void operator delete[](void*) throw()noexcept;
</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()noexcept;
void operator delete(void*, void*) throw()noexcept;
void operator delete[](void*, const std::nothrow_t&) throw()noexcept;
void operator delete[](void*, void*) throw()noexcept;
</syntaxhighlight>
 
In all of the overloads, the first parameter to the <code>operator delete</code> function is of type <syntaxhighlight lang="cpp" inline>void *</syntaxhighlight>, which is the address of the storage to deallocate.<ref name=Lischner2003 />
 
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=Lischner2003 />
Line 54:
 
=== 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()noexcept { return p; }
void* operator new[](std::size_t, void* p) throw()noexcept { return p; }
void operator delete(void*, void*) throw()noexcept { }
void operator delete[](void*, void*) throw()noexcept { }
</syntaxhighlight>
 
Line 83:
This operator is implemented as:
<syntaxhighlight lang="cpp">
void* operator new(std::size_t count, void* here) noexcept { return here; }
void* operator new[](std::size_t count, void* here) noexcept { return here; }
</syntaxhighlight>
 
Line 90:
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 <syntaxhighlight lang="cpp" inline>NULL</syntaxhighlight> pointer when an error occurred, is accessible via placement syntax.<ref name=Lippman1997 /><ref name=Meyers1998 /><ref name=Loudon2003 />
 
Programmers who wish to do this in their programs must include the Standard C++ library header <code>&lt;<new&gt;></code> (or import the <code>std</code> module) in the source code. This header declares the global <code>std::nothrow</code> object, which is of type <code>std::nothrow_t</code> (also declared in the header), which is used to call the overloaded new functions that are declared as taking <syntaxhighlight lang="cpp" inline>const std::nothrow_t &</syntaxhighlight> as their second parameter. For example:<ref name=Anderson1998a />
<syntaxhighlight lang="cpp">
import std;
#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) {
Line 109:
 
=== Custom allocators ===
Placement syntax is also employed for custom [[allocator (C++)|allocators]]. This does not use any of the allocator and deallocator functions from the Standard C++ library header <code>&lt;<new&gt;</code>, but requires that programmers write their own allocation and deallocation functions, overloaded for user-defined types. For example, one could define a memory management class as follows:<ref name=Vermeir2001 /><ref name=Stroustrup1997b />
<syntaxhighlight lang="cpp">
import std;
#include <cstdlib>
 
class A {
public:
Line 160 ⟶ 161:
/* ... */
p->~T(); // First invoke the destructor explicitly.
operator delete(p, arena); // Then call the deallocator function indirectly via operator delete(void*, A &).
</syntaxhighlight>
 
Line 186 ⟶ 187:
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=Anderson1998a /><ref name=Yongwei2007 />
<syntaxhighlight lang="cpp">
import std;
#include <new>
#include <cstdlib>
 
class NewErrorAlloationError {
public:
NewErrorAlloationError(const char* file, int line) { /* ... */ }
/* ... */
} ;
 
void* operator new(std::size_t size, 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 NewErrorAlloationError(file, line);
}
</syntaxhighlight>
Line 209 ⟶ 207:
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=Lischner2003 /><ref name=Meyers1998 /><ref name=SolterKleper2005 /><ref name=Anderson1998b />
 
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=Lischner2003 /><ref name=SolterKleper2005 /><ref name=Anderson1998b />
<syntaxhighlight lang="cpp">
import std;
#include <cstdlib>
#include <iostream>
 
struct A {};
Line 222 ⟶ 219:
};
 
void * operator new(std::size_t, const A&) {
std::cout << println("Placement new called." << std::endl);
}
 
void operator delete(void*, const A&) {
std::cout << println("Placement delete called." << std::endl);
}
 
Line 235 ⟶ 232:
T* p = new(a) T;
} catch (E exp) {
std::cout << println("Exception caught." << std::endl);
}
return 0;
Line 241 ⟶ 238:
</syntaxhighlight>
 
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 <ref name=":0">{{Cite book|last1=Kundu|first1=Ashish|last2=Bertino|first2=Elisa|title=2011 31st International Conference on Distributed Computing Systems |chapter=A New Class of Buffer Overflow Attacks |date=June 2011|chapter-url=https://ieeexplore.ieee.org/document/5961725|pages=730–739|doi=10.1109/ICDCS.2011.63|isbn=978-1-61284-384-1 |s2cid=8583476 |via=IEEE}}</ref> be deallocated in the event of the object's constructor throwing an exception.<ref name=SolterKleper2005 />
 
If no matching placement delete function exists, no deallocation function is called in the event of an exception being thrown by a constructor within a placement <code>new</code> expression. There are also some (older) C++ implementations that do not support placement delete (which, like the exception-throwing allocator functions, were an addition made to C++ when it was standardized) at all. In both such situations, an exception being thrown by a constructor when allocating using a custom allocator will result in a memory leak. (In the case of the older C++ implementations, a memory leak will also occur with ''non-''placement <code>new</code> expressions.)<ref name=Meyers1998 /><ref name=Anderson1998b />
Line 281 ⟶ 278:
* {{cite book|title=An Introduction to Object-oriented Programming in C++|first1=Graham M.|last1=Seed|first2=Barry J.|last2=Cooper|publisher=Springer|year=2001|isbn=1-85233-450-9|edition=Second}}
* {{cite book|title=Professional C++|first1=Nicholas|last1=Solter|first2=Scott|last2=Kleper|publisher=Wiley|year=2005|isbn=9780764574849}}
* {{cite book|title=The C++ Programming Language|edition=2nd|first=Bjarne|last=Stroustrup|author-link=Bjarne Stroustrup|isbn=978-0-201-53992-9|date=July 1991|publisher=Pearson Education Canada |url-access=registration|url=https://archive.org/details/cprogramminglang00stro}}
* {{cite book|last=Stroustrup|first=Bjarne|author-link=Bjarne Stroustrup|title=Design and Evolution of C++|publisher=[[Addison-Wesley]]|isbn=978-0-201-54330-8|year=1994|chapter=Memory Management}}
* {{cite book|last=Stroustrup|first=Bjarne|author-link=Bjarne Stroustrup|title=The C++ Programming Language|publisher=[[Addison-Wesley]]|edition=3rd|isbn=978-0-201-88954-3|year=1997|url-access=registration|url=https://archive.org/details/cprogramminglang00stro_0}}