布局兼容类型的联合

gez*_*eza 11 c++ unions language-lawyer standard-layout c++17

看看这段代码:

struct A {
    short s;
    int i;
};
struct B {
    short s;
    int i;
};

union U {
    A a;
    B b;
};

int fn() {
    U u;
    u.a.i = 1;
    return u.b.i;
}
Run Code Online (Sandbox Code Playgroud)

是否保证fn()退货1

注:这是一个后续问题要这个.

Nat*_*ica 10

是的,这是定义的行为.首先让我们看看标准的含义AB. [class.prop]/3

类S是标准布局类,如果它:

  • 没有非标准布局类(或此类类型的数组)或引用类型的非静态数据成员,
  • 没有虚函数,也没有虚基类,
  • 对所有非静态数据成员具有相同的访问控制,
  • 没有非标准布局基类,
  • 最多有一个任何给定类型的基类子对象,
  • 具有类中的所有非静态数据成员和位字段及其基类首先在同一个类中声明,并且
  • [...](这里没有任何说法在这种情况下有任何影响)

所以AB都是标准布局类型.如果我们看一下[class.mem]/23

如果两个标准布局结构类型的公共初始序列包含两个类的所有成员和位字段([basic.types]),则它们是布局兼容类.

[class.mem]/22

两个标准布局结构类型的公共初始序列是声明顺序中最长的非静态数据成员序列和位字段,从每个结构中的第一个这样的实体开始,使得对应的实体具有布局兼容类型,两个实体都使用no_unique_address属性([dcl.attr.nouniqueaddr])声明,或两者都没有,并且两个实体都是具有相同宽度的位字段,或者都不是位字段.

[class.mem]/25

在具有struct类型T1的活动成员的标准布局并集中,允许读取结构类型T2的另一个union成员的非静态数据成员m,前提是m是T1和T2的公共初始序列的一部分; 行为就像提名T1的相应成员一样.[例如:

struct T1 { int a, b; };
struct T2 { int c; double d; };
union U { T1 t1; T2 t2; };
int f() {
  U u = { { 1, 2 } };   // active member is t1
  return u.t2.c;        // OK, as if u.t1.a were nominated
}
Run Code Online (Sandbox Code Playgroud)

- 结束示例] [注意:通过非易失性类型的glvalue读取volatile对象具有未定义的行为([dcl.type.cv]). - 结束说明]

然后我们假设类具有相同的公共初始序列,布局相同,并且访问非活动类型的相同成员被视为访问活动类型的该成员.