【问题标题】:Union of layout-compatible types布局兼容类型的联合
【发布时间】:2019-04-02 17:09: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;
}

是否保证fn() 返回1

注意:这是this 的后续问题。

【问题讨论】:

    标签: c++ language-lawyer c++17 unions standard-layout


    【解决方案1】:

    是的,这是已定义的行为。首先让我们看看标准对AB 有什么看法。 [class.prop]/3

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

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

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

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

    [class.mem]/22

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

    [class.mem]/25

    在具有结构类型 T1 的活动成员的标准布局联合中,允许读取结构类型 T2 的另一个联合成员的非静态数据成员 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
    }
    

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

    那么我们得到类具有相同的公共初始序列,布局相同,访问非活动类型的相同成员被视为访问活动类型的该成员。

    【讨论】:

    • 是否保证A::iB::ioffsetof是一样的?文字只是说“好的,......提名”。或者什么保证 1 会被返回?当然,这似乎是合乎逻辑的,我只是看不到它的保证。即使存在共同的初始序列。我不能保证通用的初始序列布局相同。还是在某处得到保证?
    • @geza 在代码上面的文字中:行为就好像T1的相应成员被提名了一样。
    • @geza 让我再补充一点,以表明类的布局必须相同
    • @NathanOliver u 在 OP 问题中有活跃成员吗?
    • @Jans 从我的阅读中u.a.i = 1; 使其活跃:timsong-cpp.github.io/cppwp/class.union#5
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-02
    • 2018-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多