reinterpret_cast creating a trivially default-constructible object
There is no X
object, living or otherwise, so pretending that there is one results in undefined behavior.
[intro.object]/1 spells out exhaustively when objects are created:
An object is created by a definition ([basic.def]), by a new-expression ([expr.new]), when implicitly changing the active member of a union ([class.union]), or when a temporary object is created ([conv.rval], [class.temporary]).
With the adoption of P0137R1, this paragraph is the definition of the term "object".
Is there a definition of an X
object? No. Is there a new-expression? No. Is there a union? No. Is there a language construct in your code that creates a temporary X
object? No.
Whatever [basic.life] says about the lifetime of an object with vacuous initialization is irrelevant. For that to apply, you have to have an object in the first place. You don't.
C++11 has roughly the same paragraph, but doesn't use it as the definition of "object". Nonetheless, the interpretation is the same. The alternative interpretation - treating [basic.life] as creating an object as soon as suitable storage is obtained - means that you are creating Schrödinger's objects*, which contradicts N3337 [intro.object]/6:
Two objects that are not bit-fields may have the same address if one is a subobject of the other, or if at least one is a base class subobject of zero size and they are of different types; otherwise, they shall have distinct addresses.
* Storage with the proper alignment and size for a type T
is by definition storage with the proper alignment and size for every other type whose size and alignment requirements are equal to or less than those of T
. Thus, that interpretation means that obtaining the storage simultaneously creates an infinite set of objects with different types in said storage, all having the same address.
Based on p0593r6 I believe the code in the OP is valid and should be well defined. The new wording, based on the DR retroactively applied to all versions from C++98 inclusive, allows implicitly object creation as long as the created object is well defined (tautology is sometimes the rescue for complicated definitions), see § 6.7.2.11 Object model [intro.object]):
implicitly-created objects whose address is the address of the start of the region of storage, and produce a pointer value that points to that object, if that value would result in the program having defined behavior [...]
See also: https://stackoverflow.com/a/61999151/2085626