P0593, under the Type punning section, presents this example:
float do_bad_things(int n) {
alignof(int) alignof(float)
char buffer[max(sizeof(int), sizeof(float))];
*(int*)buffer = n; // #1
new (buffer) std::byte[sizeof(buffer)];
return *(float*)buffer; // #2
}
And states that:
The proposed rule would permit an
int
object to spring into existence to make line #1 valid [...], and would permit afloat
object to likewise spring into existence to make line #2 valid.However, these examples still do not have defined behavior under the proposed rule. The reason is a consequence of [basic.life]p4:
The properties ascribed to objects and references throughout this document apply for a given object or reference only during its lifetime.
Specifically, the value held by an object is only stable throughout its lifetime. When the lifetime of the
int
object in line #1 ends (when its storage is reused by thefloat
object in line #2), its value is gone. Symmetrically, when the float object is created, the object has an indeterminate value ([dcl.init]p12), and therefore any attempt to load its value results in undefined behavior.
emphasis mine
The proposal claims that the problematic part is the (implicit) creation of a float
object. But isn't the previous line (new (buffer) std::byte[sizeof(buffer)]
) already reusing the storage (by creating a byte
array), ending the lifetime of the int
in question? To my understanding, placement-new always ends the lifetime of the object that lived in the memory in which a new object is being created.
Also, this comment says that "New expressions do not promise to preserve the bytes in the storage." Would that mean that new (buffer) std::byte[sizeof(buffer)]
could theoretically alter the bytes from buffer
, effectively getting rid of the value that we wished to pun?
Just to be clear, I am not looking for a way to achieve type punning. Those are just examples that fit the best for me (that I found so far) to understand the underlying mechanisms of nowadays lifetime management.
std::byte[sizeof(buffer)]
array that creates objects implicitly. No need to save any pointer to it. Besides, I don't see how that aligns with the question. Maybe the title is a bit misleading, though – Firewaterstd::byte
array elements – Notationnew (buffer) std::byte[sizeof(buffer)]
is guaranteed to preserve the value that the (now dead)int
had? – Firewater