This question is based on this
Consider the following:
struct Hdr { int type; };
struct A { Hdr h; };
union Big {
Hdr h;
A a;
};
and suppose that for Big big
we know that big.a
is the active member of the union. Is the access to big.h.type
undefined behavior?
I think is indeed UB, based on:
class.union
... [ 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 ([class.mem]), 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 ]
We have a standard layout union which has standard layout member structs but as understand it, the common initial sequence for Hdr
and A
is empty even though the first data member of A
is of type of Hdr
.
Am I right in that this is UB ? if not, which point of common initial sequence I misunderstood so that the access big.h.type
is defined ?
I see no fault in your interpretation.
As per your quote, this is well defined only if A
and Hdr
share a common initial sequence that includes Hdr::type
.
To quote the rule that defines the common initial sequence:
[class.mem] The common initial sequence of two standard-layout struct ([class.prop]) types is the longest sequence of non-static data members and bit-fields in declaration order, starting with the first such entity in each of the structs, such that corresponding entities have layout-compatible types ...
So, the first members of A
and Hdr
are common if they - that is int
and Hdr
- are layout-compatible types. That is specified in
[basic.types] Two types cv1 T1 and cv2 T2 are layout-compatible types if T1 and T2 are the same type (they are not the same type), layout-compatible enumerations (they are not enumerations), or layout-compatible standard-layout class types (only one of them is a class type).
As none apply, int
and Hdr
are not layout-compatible, and therefore the common initial sequence of A
and Hdr
is empty and therefore there is no member to which the quoted special guarantee applies.
You could use a wrapper to get around the subtlety of the rule:
union Big {
struct {
Hdr h;
} w;
A a;
} big;
Here, accessing big.w.h.type
would be well defined even if big.a
is active. P.S. Anonymous struct would be nice here to make the wrapper invisible. Unfortunately those are ill-formed in standard C++.
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