Which parts of a modern C++ standard (C++20 or C++23 are fine) say that it's not okay to destroy an object twice using placement new and an explicit destructor call?
alignas(T) std::byte storage[sizeof(T)];
T* const p = new (storage) T(...);
p->~T();
p->~T();
Are there any conditions this is allowed, e.g. if T has a trivial destructor?
I found this previous answer to a semi-related question that gives a relatively clear answer the the trivial destructor part of the question, but it uses C++17 and to my surprise the wording in C++20 seems to have changed to also forbid this for trivial destructors. This seems like it should be fine for trivial destructors, so I suspect I'm missing something.
[basic.life]/6.2
... after the lifetime of an object has ended ... The program has undefined behavior if:
— the pointer is used to ... call a non-static member function of the object
Now are destructors non-static member functions? Yes, [class.mem.special]/1.
...Or, if this is a pseudo-destructor call (i.e. if T is non-class), then it's UB for a different reason. [expr.call]/4 says it ends the lifetime of an object, and if there's no object (because its lifetime has already ended), the precondition is false so the behavior is undefined.
Are there any conditions this is allowed, e.g. if T has a trivial destructor?
Doesn't seem to be the case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With