使用 `` 在 C++ 中聚合初始化联合

Posted

技术标签:

【中文标题】使用 `` 在 C++ 中聚合初始化联合【英文标题】:Aggregate initialization of a union in C++ with ``使用 `` 在 C++ 中聚合初始化联合 【发布时间】:2021-10-23 03:26:44 【问题描述】:

在下面的程序中,联合 U 有两个字段 ab,每个字段都有不同的默认值。如果使用聚合初始化创建U 类型的变量 联合的值和活动成员是什么?

#include <iostream>

struct A  int x = 1; ;
struct B  int x = 0; ;

union U 
    A a;
    B b;
;

int main() 
    U u;
    std::cout << u.a.x;

令人惊讶的是编译器在这里出现了分歧:Clang 打印 1 和 GCC 打印 0,演示:https://gcc.godbolt.org/z/8Tj4Y1Pv1

其中一个编译器是否存在错误或此处的行为未由标准定义?

【问题讨论】:

当你初始化u时,你正在做value initialization。而且由于U不是类类型,所以会导致u成为zero initialized。 令人惊讶的是编译器在这里出现分歧:Clang 打印 1 和 GCC 打印 0 - 似乎有缺陷,应该是 0 @Someprogrammerdude U 是一个类类型,它是联合聚合类。注意规范性术语“non-union aggregate”,例如在 [dcl.init.aggr]/5 中使用。因此,这是聚合初始化,并且 [dcl.init.aggr]/5 适用(/5.5 表示 U u;,然后 /5.1 表示联合的第一个数据成员 a)。 【参考方案1】:

Clang 正确,GCC 错误

根据[dcl.init.aggr]/1:

聚合是一个数组或一个类([class])

(1.1) 没有用户声明或继承的构造函数 ([class.ctor]), (1.2) 没有私有或受保护的直接非静态数据成员 ([class.access]), (1.3) 没有虚函数 ([class.virtual]),并且 (1.4) 没有虚拟、私有或受保护的基类 ([class.mi])。

ABU 都是聚合类,虽然前面是 非联合 聚合类,前者不符合条件。

根据[dcl.init.aggr]/5 [强调我的]:

对于非联合聚合,每个不是显式 初始化元素的初始化如下:

(5.1) 如果元素具有默认成员初始化程序 ([class.mem]),则从该初始化程序初始化元素。 (5.2) 否则,如果元素不是引用,则从空的初始化列表 ([dcl.init.list]) 复制初始化该元素。 (5.3) 否则,程序格式错误。

如果聚合是一个联合并且初始化列表为空,那么

(5.4) 如果任何变体成员具有默认成员初始化程序,则该成员从其默认成员初始化程序初始化; (5.5) 否则,联合体的第一个成员(如果有)将从空的初始化列表复制初始化。

这样

U u;

是聚合初始化,结果是联合类的第一个数据成员,即A类型的数据成员a(这是一个非联合聚合类),从一个空的初始化列表。由于A类型的单个数据成员x有一个默认的成员初始化器,那么根据上面的[dcl.init.aggr]/5.1,数据成员x由它的默认成员初始化器初始化。

因此,Clang 是正确的,而 GCC 是错误的。


GCC 错误报告

Bug 102013 - Incorrect aggregate initialization of union

【讨论】:

MSVC 也打印 0 @MarcinPoloczek 我通常对 MSVC 在 GCC 和 Clang 不同意的语言极端情况下的行为没有什么价值。在这种特殊情况下,afaict Clang 正在按照标准实现正确的行为。 是的,您的答案似乎是正确的。我错过了细节。我已经删除了我的帖子。

以上是关于使用 `` 在 C++ 中聚合初始化联合的主要内容,如果未能解决你的问题,请参考以下文章

C++ 中的聚合初始化安全

C++ 中聚合的带括号初始化的模板参数推导

constexpr 在联合中初始化结构时,msvc visual c++ 静默错误代码生成

C++ - 成员变量聚合初始化

可以使用 C++ 聚合初始化来构造实现接口的类的实例吗?

C++ 不能用初始值设定项列表初始化非聚合错误