I was looking to re-use allocated space within the base class from this pointer and C++ Standard does not approve. However, the wording of the standard seems to be wrong. It puts a condition "and before the storage which the object occupied is reused or released", but it is clearly reused in their own code snippet. Where I am getting it wrong?
void B::mutate() {
new (this) D2; // reuses storage — ends the lifetime of *this!! REUSED AS WELL SO CONDITION SO RESTRICTIONS DON'T HOLD ANYMORE!
f(); // undefined behavior
Before the lifetime of an object has started but after the storage which the object will occupy has been allocated41 or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that represents the address of the storage location where the object will be or was located may be used but only in limited ways. For an object under construction or destruction, see [class.cdtor]. Otherwise, such a pointer refers to allocated storage ([basic.stc.dynamic.deallocation]), and using the pointer as if the pointer were of type void*, is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The program has undefined behavior if:
(6.1) the object will be or was of a class type with a non-trivial destructor and the pointer is used as the operand of a delete-expression,
(6.2) the pointer is used to access a non-static data member or call a non-static member function of the object, or
(6.3) the pointer is implicitly converted ([conv.ptr]) to a pointer to a virtual base class, or
(6.4) the pointer is used as the operand of a static_cast, except when the conversion is to pointer to cv void, or to pointer to cv void and subsequently to pointer to cv char, cv unsigned char, or cv std::byte ([cstddef.syn]), or
(6.5) the pointer is used as the operand of a dynamic_cast.
[ Example:
#include <cstdlib> struct B { virtual void f(); void mutate(); virtual ~B(); }; struct D1 : B { void f(); }; struct D2 : B { void f(); }; /* RELEVANT PART STARTS */ void B::mutate() { new (this) D2; // reuses storage — ends the lifetime of *this f(); // undefined behavior /* RELEVANT PART ENDS */ ... = this; // OK, this points to valid memory } void g() { void* p = std::malloc(sizeof(D1) + sizeof(D2)); B* pb = new (p) D1; pb->mutate(); *pb; // OK: pb points to valid memory void* q = pb; // OK: pb points to valid memory pb->f(); // undefined behavior, lifetime of *pb has ended }