I was messing with placement new, and made this code:
#include <iostream>
#include <functional>
#include <new>
int main()
{
char memory[sizeof(int)]; //memory to hold type
auto ref = std::ref(*new (memory) int{5}); //allocating int in memory, and make a reference to it
std::cout << ref << std::endl;
new (memory) unsigned{6}; //"overwrite"
std::cout << ref << std::endl;
}
The output is 5
then 6
, but is it well defined? If so, would it be okay if I used float
as second type instead?
The second placement new-expression reuses the storage of, and therefore ends the lifetime of, the int
object created by the first placement new-expression ([basic.life]/1.4).
Since [basic.life]/8 isn't satisfied (due to the type difference), the pointer stored by the reference wrapper doesn't point to the new object, but continues to point to the out-of-lifetime int
object. Accessing the object via an lvalue obtained from such a pointer therefore has undefined behavior per [basic.life]/7.
Note that strict aliasing is irrelevant here; that rule explicitly permits accessing an object via a glvalue of "a type that is the signed or unsigned type corresponding to the dynamic type of the object".