C++20 has added destroying form of operator delete
distinguished by the std::destroying_delete_t
parameter. It causes delete
expression to no longer destroy the object prior to invoking operator delete
.
The intention is to allow customization of deletion in a way that depends on the object's state, before explicitly invoking the object's destructor and deallocating memory.
However, it isn't clear to me if, when implementing such an operator, I'm actually required to destroy the object. Specifically, am I allowed to have a pool of static objects, and give them out to users who can subsequently treat them as-if they were dynamically allocated? Such that delete
expression executed on the object will merely return it to the pool without destroying it. For example, is the following program well-defined?
#include <new>
struct A {
virtual ~A() = default;
};
// 'Regular' dynamically allocated objects
struct B : A {
static A* create() {
return new B();
}
private:
B() = default;
};
// Pooled, statically allocated objects
struct C : A {
static A* create() {
for (auto& c: pool) {
if (!c.in_use) {
c.in_use = true;
return &c;
}
}
throw std::bad_alloc();
}
private:
static C pool[3];
bool in_use = false;
C() = default;
void operator delete(C *c, std::destroying_delete_t) {
c->in_use = false;
}
};
C C::pool[3];
// Delete them identically via the common interface.
void do_something_and_delete(A* a) {
delete a;
}
int main() {
do_something_and_delete(B::create());
do_something_and_delete(B::create());
do_something_and_delete(C::create());
do_something_and_delete(C::create());
}
virtual
functions is not 'lying' in exactly the same way? The user shouldn't care if the object is 'really' destroyed. From their perspective they aren't allowed to dereferencewhatever
afterdelete whatever;
in either case. It's just abstraction. – Ruminate