Item 52: Write placement delete if you write placement new
Concept
When a new expression allocates memory and the constructor throws, the runtime must deallocate the memory using a matching operator delete. A "placement" version of operator new is any version taking extra parameters beyond std::size_t. If you write a placement operator new, you must also write a matching placement operator delete (same extra parameters) — otherwise memory will leak when constructors throw. Additionally, declaring any operator new in a class hides the standard forms, so use using declarations to keep them accessible.
Code Example
#include <new>
#include <iostream>
class Widget {
public:
// Placement new: logs allocation
static void* operator new(std::size_t size, std::ostream& log) {
log << "Allocating " << size << " bytes\n";
return ::operator new(size);
}
// Matching placement delete — MUST exist!
// Called if constructor throws after placement new succeeds
static void operator delete(void* pMemory, std::ostream& log) noexcept {
log << "Deallocating due to constructor failure\n";
::operator delete(pMemory);
}
// Normal delete for regular deallocation
static void operator delete(void* pMemory) noexcept {
::operator delete(pMemory);
}
// Unhide standard forms
using Base = void; // Placeholder; in practice:
// static void* operator new(std::size_t size);
// static void* operator new(std::size_t, void*);
// static void* operator new(std::size_t, const std::nothrow_t&);
};
// Usage:
// Widget* pw = new (std::cerr) Widget; // Uses placement new
Things to Remember
- When you write a placement version of
operator new, be sure to write the corresponding placement version ofoperator delete. If you don't, your program may experience subtle, intermittent memory leaks. - When you declare placement versions of
newanddelete, be sure not to unintentionally hide the normal versions of those functions.