In C++, it's well-defined to read from an union member which was most recently written, aka the active union member.
My question is whether std::memcpy
ing a whole union object, as opposed to copying a particular union member, to an uninitialized memory area will preserve the active union member.
union A {
int x;
char y[4];
};
A a;
a.y[0] = 'U';
a.y[1] = 'B';
a.y[2] = '?';
a.y[3] = '\0';
std::byte buf[sizeof(A)];
std::memcpy(buf, &a, sizeof(A));
A& a2 = *reinterpret_cast<A*>(buf);
std::cout << a2.y << '\n'; // is `A::y` the active member of `a2`?
The assignments you have are okay because the assignment to non-class member a.y
"begins its lifetime". However, your std::memcpy
does not do that, so any accesses to members of a2
are invalid. So, you are relying on the consequences of undefined behaviour. Technically. In practice most toolchains are rather lax about aliasing and lifetime of primitive-type union members.
Unfortunately, there's more UB here, in that you're violating aliasing for the union itself: you can pretend that a T
is a bunch of bytes, but you can't pretend that a bunch of bytes is a T
, no matter how much reinterpret_cast
ing you do. You could instantiate an A a2
normally and std::copy
/std::memcpy
over it from a
, and then you're just back to the union member lifetime problem, if you care about that. But, I guess, if this option were open to you, you'd just be writing A a2 = a
in the first place…