标准中的哪个地方说编译器应该忽略U :: j的默认成员初始值设定项?

时间:2016-11-16 13:21:43

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

请考虑以下代码段:

#include <iostream>
union U{
    U(): i(1) {}
    int i;
    int j = 2;    // this default member initializer is ignored by the compiler
};

U u;

int main(){
    std::cout << u.i << '\n';
    std::cout << u.j << '\n';
}

代码打印(参见live example):

1
1

标准中的哪个部分表示编译器忽略了成员U::j的默认成员初始值设定项?

请注意,根据[class.union.anon]/4,下面的联合没有编译,这是可以的。因此我期待上面的代码片段也不会编译。

请参阅live example

union U{
    int i = 1;
    int j = 2;
};

2 个答案:

答案 0 :(得分:7)

  

标准中的哪个部分表示编译器忽略了成员U :: j的默认成员初始值设定项?

参见C ++ 17 CD中的[class.base.init]第9段子弹9.1。

N.B。您的演示具有未定义的行为,因为联合的活动成员是i,但您从j读取。这适用于某些编译器作为非标准扩展,但在ISO C ++中不允许。

答案 1 :(得分:3)

请注意,您正在声明一个union对象,其中所有成员共享相同的内存区域 - 成员变量会转换为相同数据的不同“类型视图”。

因此,当成员i和j有效地存储在同一个内存位置时,您在j上执行的任何初始化(使用初始化程序)都将被构造函数设置i覆盖。

只是为了测试,从构造函数中删除i的初始化:

#include <iostream>
union U{
    U() {}
    int i;
    int j = 2;    // this initializes both i & j
};

U u;

int main(){
    std::cout << u.i << '\n';
    std::cout << u.j << '\n';   
}

输出为

2
2

更新: 根据@Ayrosa评论并且只是好奇,我修改了原始片段以使用函数(而不是常量)执行一些初始化以引发副作用。

#include <iostream>

int static someStatic()
{
    std::cout << "Initializer was not ignored\n";
    return(2);
}

union U{
    U(): i(1) {}
    int i;
    int j = someStatic();    // this default member initializer is ignored by the compiler
};

U u;

int main(){
    std::cout << u.i << '\n';
    std::cout << u.j << '\n';
}

结果是:

1
1

这意味着编译器忽略了对someStatic()的调用。