c++language-lawyerc++20

Is it valid to call std::destroy_at on a unconstructed object?


When I was reading the sample code of std::construct_at at cppref, I noticed that std::destroy_at is called on a uninitialized buffer:

alignas(S) unsigned char storage[sizeof(S)]{};
S uninitialized = std::bit_cast<S>(storage);
std::destroy_at(&uninitialized);

I somehow believed that this should be UB operation because lifecycle of object is not started yet. Is calling std::destroy_at on an uninitialized buffer a valid operation by c++ standard?


Solution

  • It's wrong to call std::destroy_at on an unconstructed object - that would be UB.

    But that's not what's happening here. It's being called on the S object at uninitialized, not on storage. The latter seems to be a red herring - there's no good reason for constructing uninitialized from random bytes rather than simply aggregate-initializing it.

    A clearer example would omit the red-herring storage variable:

    S uninitialized{0, 0.0f, 0.0};
    std::destroy_at(&uninitialized);
    

    There is a real bug in the example: we have

    std::destroy_at(ptr);
    

    and ptr points to uninitialized. So at end of scope, we have a second destruction of the same object, which is UB.

    If that line is removed, the example becomes valid.