c++undefined-behaviorlifetime

Is it UB to skip the destructor of a derived class before doing a placement new on a base class?


At https://en.cppreference.com/w/cpp/utility/launder.html, there is an example as follows (simplified for brevity, comments mine):

struct Base
{
    virtual int transmogrify();
};
 
struct Derived : Base
{
    int transmogrify() override
    {
        // missing this->~Derived();?
        new(this) Base;
        return 2;
    }
};
 
int Base::transmogrify()
{
    // missing this->~Base();?
    new(this) Derived;
    return 1;
}

Is the above example incorrect (containing UB)?


Solution

  • According to the C++ standard [basic.life] you implicitly end the lifetime of the object by reusing its storage, this skips calling the destructor. and trivially destructible objects have no destructor so it can safely be skipped.

    The lifetime of an object o of type T ends when:

    • ...
    • the storage which the object occupies is released, or is reused by an object that is not nested within o ([intro.object]).
    1. A program may end the lifetime of an object of class type without invoking the destructor, by reusing or releasing the storage as described above.
    1. If a program ends the lifetime of an object of type T with static ([basic.stc.static]), thread ([basic.stc.thread]), or automatic ([basic.stc.auto]) storage duration and if T has a non-trivial destructor and another object of the original type does not occupy that same storage location when the implicit destructor call takes place, the behavior of the program is undefined.

    skipping calling the destructor is not UB (memory leaks are not UB), but since the object has automatic storage duration it will be undefined only if the class has a non-trivial destructor, and in your example both Base and Derived are trivially destructible, therefore this is NOT UB.