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?
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.