C++11 空列表初始化联合 - 是不是保证初始化联合的全长?
Posted
技术标签:
【中文标题】C++11 空列表初始化联合 - 是不是保证初始化联合的全长?【英文标题】:C++11 empty list Initialization of a union - is it guaranteed to initialize the full length of the union?C++11 空列表初始化联合 - 是否保证初始化联合的全长? 【发布时间】:2017-03-01 14:56:30 【问题描述】:在 C++11 中,我有以下联合:
union SomeData
std::uint8_t Byte;
std::uint16_t Word;
std::uint32_t DWord;
unsigned char String[128];
;
如果我这样初始化联合;
SomeData data ;
是否保证联合的整个内容将被“归零”?换一种方式;是一个联合的空列表初始化器功能上等效到memset-ing联合为零?:
memset(&data, 0, sizeof(data));
我特别关心字符串数据。我想确保字符串的整个长度都包含零。它似乎在我当前的编译器中工作,但 规范的语言 是否保证这始终是正确的?
如果没有:有没有更好的方法将联合的全长初始化为零?
【问题讨论】:
【参考方案1】:不,不能保证整个工会都会被清零。只有联合的第一个声明的成员,加上任何填充,保证为零(证明如下)。
因此,要确保联合对象的整个内存区域为零,您有以下选择:
对成员进行排序,使最大的成员排在第一位,从而将其清零。 使用std::memset
或等效功能。为防止意外忘记这一点,您当然可以给 SomeData
一个默认构造函数,它会调用它。
引用 C++11:
8.5.4 [dcl.init.list]/3
如果初始值设定项列表没有元素并且
T
类型的对象或引用的列表初始化定义如下:T
是具有默认构造函数的类类型,则对象为 值初始化。
8.5 [dcl.init]/7
值初始化
如果T
类型的对象意味着:T
是具有用户提供的构造函数 (12.1) 的(可能是 cv 限定的)类类型(第 9 条),则 调用T
的默认构造函数(如果T
没有可访问的默认值,则初始化格式错误 构造函数); 如果T
是一个(可能是 cv 限定的)非联合类类型,没有用户提供的构造函数,那么对象 是零初始化的,如果T
的隐式声明的默认构造函数是非平凡的,则该构造函数是 调用。 ... 否则,对象被零初始化。
8.5 [dcl.init]/5:
零初始化
T
类型的对象或引用意味着:...
如果T
是(可能是cv 限定的)联合类型,则对象的第一个非静态命名数据成员为零初始化 并且填充被初始化为零位;
从这些引用中,您可以看到使用 来初始化
data
将导致对象被值初始化(因为SomeData
是具有默认构造函数的类类型)。
在没有用户提供的默认构造函数(SomeData
是)的情况下对联合进行值初始化意味着对其进行零初始化。
最后,零初始化联合意味着零初始化它的第一个非静态命名数据成员。
【讨论】:
这太糟糕了。有没有一种简单的方法可以将完整的联合初始化为零?还是“memset”是唯一的方法? @BTownTKD 把最大的成员放在第一位? 哦。是的。杜普。 我对padding被初始化为零位的理解是union的剩余部分会被设置为0。 这是core issue 694。声明的意图是将整个工会归零。【参考方案2】:整个联合将被清零。更确切地说,联合的第一个成员将被默认初始化,联合中所有剩余的字节将设置为 0 作为 padding。
参考文献(强调我的):
8.5 初始化程序 [dcl.init]...
5 对 T 类型的对象或引用进行零初始化意味着:... — 如果 T 是(可能是 cv 限定的)联合类型,则对象的第一个非静态命名数据成员初始化为零 并且填充被初始化为零位;
这意味着联合的第一个成员(此处为 std::uint8_t Byte;
)将被初始化为 0,联合中的所有其他字节将被设置为 0,因为它们是填充字节。
但是小心。正如 Angew 所述,“padding”在标准中没有得到很好的说明,C 编译器可以解释为联合中的填充字节只是最大成员之后的字节。我真的会觉得这很奇怪,因为兼容性更改是专门记录的,并且以前的版本 (C) 首先将所有内容初始化为 0,然后进行特定的初始化。但是一个新的实现者无法意识到这一点......
TL/DR:我真的认为标准的意图是在 OP 的示例中联合中的所有字节都设置为 0,但是对于关键任务程序,我肯定会添加一个显式的 0 构造函数...
【讨论】:
有趣!这确实是一个令人愉快的解释。规范中是否有任何内容阐明了联合中“填充”的定义? 有趣。当然,这确实意味着每个人都需要将最大的成员放在联合中的第一位,以使整个联合初始化为零,对吗? @SJHowe 更准确地说,如果联合中的第一个成员是最大的,那么您确定联合中的所有字节都将设置为 0。以上是关于C++11 空列表初始化联合 - 是不是保证初始化联合的全长?的主要内容,如果未能解决你的问题,请参考以下文章