In the union U
below, if a
or b
is the active member, is it defined behavior to access c
?
struct A{
int a;
};
struct B{
int a;
double b;
};
union U{
A a;
B b;
int c;
};
In [class.union], the standard defines some rules to make using a union
easier (emphasis mine):
[ Note: One special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence, and if a non-static data member of an object of this standard-layout union type is active and is one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of the standard-layout struct members; see [class.mem]. — end note ]
I'm hung up on the word struct here. Does a standard layout scalar like int
count even though it's not a struct?
My union U
above is indeed a "standard-layout" union following [class] that basically says it needs to be a standard layout class that uses the union
keyword instead, and since we only use scalars (standard layout types), it passes.
The structs obviously share a common initial sequence that consists of the first int
member, but it's unclear if fundamental types can be considered for common initial sequences.
int
elements in the standard layout structs, and the non-static int c
in the union are guaranteed to align.struct A
and struct B
are:
union U
,So, they satisfy the description in the sentence “If a standard-layout union contains several standard-layout structs that share a common initial sequence…”.
The int c
that is also in the union is not such a struct nor is it in such a struct. So this sentence is not telling you that you can write to c
and inspect a.a
or b.a
, nor that you can write to a.a
or b.a
and inspect c
.
This means that c
is not part of the common initial sequence you can inspect. But neither does it spoil the common initial sequence of struct A
and struct B
.
Regarding the text “Each non-static data member is allocated as if it were the sole member of a struct," the standard is being a bit sloppy with language here. Allocation usually refers to acquiring or reserving storage, but this use seems to refer to laying out the bytes of an object within given storage. I do not see a formal definition in the C++ standard (but I did not look too hard), but I did find a similar use. So I take it to mean that each non-static data member is laid out as if it were the sole member.
What this says is that a pointer to any one of these union members points to the same place as a pointer to any of the other union members. This may imply that pointers to one can be converted to pointers to the other. However, it does not give you license to violate the strict-aliasing rules. Even if x
is a pointer to c
and y
is a pointer to a
or a.a
, you cannot use *x
to access c
while a
is the last-written member or use *y
while c
is the last-written member.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With