这个问题是基于this
考虑以下:
struct Hdr { int type; };
struct A { Hdr h; };
union Big {
Hdr h;
A a;
};
并且假设对Big big
我们知道big.a
是联盟的活跃成员。是否可以访问big.h.type
未定义的行为?
我认为确实是UB,基于:
... [注意:为了简化联合的使用,我们做了一个特殊的保证:如果标准布局联合包含几个共享一个公共初始序列([class.mem])的标准布局结构,如果是非此标准布局联合类型的对象的静态数据成员是活动的并且是标准布局结构之一,允许检查任何标准布局结构成员的公共初始序列;见[class.mem]。 - 结束说明]
我们有一个标准的布局联合,它有标准的布局成员结构但是理解它,common initial sequence和Hdr
的A
是空的,即使A
的第一个数据成员是Hdr
的类型。
我是对的,这是UB吗?如果没有,我误解了哪个常见的初始序列,以便定义访问big.h.type
?
我认为你的解释没有错。
根据你的引用,只有当A
和Hdr
共享一个包含Hdr::type
的共同初始序列时,才能明确定义。
引用定义公共初始序列的规则:
[class.mem]两个标准布局struct([class.prop])类型的公共初始序列是声明顺序中非静态数据成员和位字段的最长序列,从每个中的第一个这样的实体开始结构,使相应的实体具有布局兼容类型......
因此,A
和Hdr
的第一个成员是常见的,如果他们 - 即int
和Hdr
- 是布局兼容的类型。这是在中指定的
[basic.types]两种类型cv1 T1和cv2 T2是布局兼容类型,如果T1和T2是相同类型(它们不是同一类型),布局兼容枚举(它们不是枚举)或布局兼容标准-layout类类型(其中只有一个是类类型)。
由于没有适用,int
和Hdr
不是布局兼容的,因此A
和Hdr
的常见初始序列是空的,因此没有引用特殊保证适用的成员。
您可以使用包装器来绕过规则的微妙之处:
union Big {
struct {
Hdr h;
} w;
A a;
} big;
在这里,即使big.w.h.type
处于活动状态,访问big.a
也会很明确。附:匿名结构在这里很好,使包装器不可见。不幸的是,这些在标准C ++中是不正确的。