C++11 空列表联合的初始化 - 是否保证初始化联合的全长?

C++11 empty list Initialization of a union - is it guaranteed to initialize the full length of the union?

在 C++11 中,我有以下联合:

union SomeData
{
    std::uint8_t Byte;
    std::uint16_t Word;
    std::uint32_t DWord;
    unsigned char String[128];
};

如果我这样初始化联合;

SomeData data {};

是否保证联合全部内容"zero'd"出来?换一种方式;是联合的空列表初始化器在功能上等同于将联合记忆设置为零?:

memset(&data, 0, sizeof(data));

我尤其关心字符串数据。我想确保字符串的整个长度都包含零。它似乎在我当前的编译器中工作,但规范的语言是否保证这始终为真?

如果不是:是否有更好的方法将并集的全长初始化为零?

不,不能保证整个联合会被归零。只有联合的第一个声明的成员,加上任何填充,保证被归零(下面的证明)。

因此,要确保联合对象的整个内存区域都归零,您有以下选择:

  • 对成员进行排序,使最大的成员排在第一位,从而将那个清零。
  • 使用std::memset 或同等功能。为了防止不小心忘记这一点,你当然可以给 SomeData 一个默认的构造函数来调用它。

引用 C++11:

8.5.4 [dcl.init.list]/3

List-initialization of an object or reference of type T is defined as follows:

  • If the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.

8.5 [dcl.init]/7

To value-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
  • if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.
  • ...
  • otherwise, the object is zero-initialized.

8.5 [dcl.init]/5:

To zero-initialize an object or reference of type T means:

...

  • if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero-initialized and padding is initialized to zero bits;

从这些引用可以看出,使用{}初始化data会导致对象被值初始化(因为SomeData是一个class类型使用默认构造函数)。

在没有用户提供的默认构造函数(SomeData 是)的情况下对联合进行值初始化意味着对其进行零初始化。

最后,零初始化联合意味着零初始化它的第一个非静态命名数据成员。

整个联盟将被清零。更确切地说,联合的第一个成员将被默认初始化,联合中的所有剩余字节将被设置为 0,如 padding.

参考文献(强调我的):

8.5 Initializers [dcl.init]
...

5 To zero-initialize an object or reference of type T means:
...
— if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero initialized and padding is initialized to zero bits;

这意味着联合的第一个成员(此处 std::uint8_t Byte;)将被初始化为 0,并且联合中的所有其他字节都将被设置为 0,因为它们是填充字节。


但是小心。正如 Angew 所说,“填充”在标准 中的定义非常少,C 编译器可以解释联合中的填充字节只是跟在最大成员之后的字节。我真的会觉得这很奇怪,因为专门记录了兼容性更改,并且以前的版本 (C) 首先将所有内容初始化为 0,然后进行特定的初始化。但是一个新的实现者可能不知道它...

TL/DR:我真的认为标准的意图是在 OP 的示例中联合中的所有字节都设置为 0,但是对于关键任务程序,我肯定会添加一个显式的 0 构造函数...