C++中{}和{0}的括号初始化有什么区别?

4

几年前我读到,在C++中使用{}和{0}来初始化POD类型可能会引入代码的不良影响。

D3D11_TEXTURE2D_DESC dsd = {};
D3D11_TEXTURE2D_DESC dsd2 = { 0 }:

虽然我知道 {0} 明显是从 c 继承而来的,而 {} 是在 c++11 中引入的,但两者在编译时都被翻译成同一个 memset() 调用:

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

然而,两种大括号初始化风格中的一种在内存初始化方面存在不对齐的问题。有人能告诉我哪种风格更好,以及为什么吗?


1
在继续之前,请跳转到godbolt并亲自查看这些东西的实际作用。可以随意设置一个测试结构,而不是D3D11_TEXTURE2D_DESC。 - Kuba hasn't forgotten Monica
使用 {} 的方式至少自 C++03 以来就存在了。 - juanchopanza
1
请查看此页面:http://en.cppreference.com/w/cpp/language/list_initialization - D Untouchable
4
我建议关闭此问题,因为它要求根据模糊的提示和关联进行猜测,推断你可能遇到了什么问题。请投反对票。 - Cheers and hth. - Alf
抱歉,我对编程还比较新,我想在提问之前需要更深入地调查和了解。 - Lazytigre
显示剩余2条评论
2个回答

10
您所提到的语法称为聚合初始化

如果初始化程序的数量少于成员数或初始化程序列表完全为空,则其余成员将进行值初始化。

由于POD类型的值初始化与零初始化相同,因此您展示的这两种语法之间没有区别。

即使在C++11之前也是如此-空初始化程序列表不是它引入的内容。自C++11以来,该语法也适用于非POD类型。聚合初始化现在是这种新列表初始化的一种特殊情况。


但是{}是默认的聚合初始化,而{0}是零聚合初始化。 - KeyC0de
@Nikos,“默认聚合初始化”或“零聚合初始化”并不存在。对于一个聚合,这两种语法都是聚合初始化。{}没有任何成员的初始化器,因此所有成员都是值初始化的,而{0}有第一个成员的初始化器,该成员从字面量0进行复制初始化,其余成员则是值初始化的。从字面量0进行复制初始化和值初始化的行为与零初始化的行为基本相同。 - eerorika
“for the first member”我觉得是对所有成员都有效,不是吗?{0}只是将class/struct中的所有内容初始化为0,是吗?而{}则会进行默认初始化/构造。我错了吗? - KeyC0de
3
{0} 中的 0 是第一个成员的初始化器。{0, 0} 将初始化两个成员。{1} 将第一个成员初始化为1。没有初始化器的其他成员将进行值初始化,对于基本类型来说是零初始化。{} 对于任何成员都没有初始化器,因此所有成员都会进行值初始化(对于基本类型来说就是零初始化)。 - eerorika

-7

两个版本都是“C++11中引入的一些东西”。大括号初始化只是调用构造函数的一种方式。例如,D3D11_TEXTURE2D_DESC dsd = {}; 调用默认构造函数,而 D3D11_TEXTURE2D_DESC dsd2 = { 0 }; 调用可以使用 const int 作为唯一参数的构造函数。除非你的构造函数之一这样做,否则它们都不会转换成类似于 memset(&dsd, 0, sizeof(dsd)); 的内容。

如果您具有隐式声明的默认构造函数,则它将简单地为该结构体的每个元素调用默认构造函数。内置类型的默认构造函数不执行任何操作,因此内存不会被设置为零。

对于那些没有定义构造函数且只有公共成员的结构体,以及一些更多限制,归结为C语言的结构体,您也可以使用聚合初始化。这基本上是您从C语言期望的。无论如何,D3D11_TEXTURE2D_DESC dsd2 = { 0 };并不等同于memset(&dsd, 0, sizeof(dsd));,因为编译器可能会为类添加填充,出于任何原因,并且当然,字段的类型在其构造函数中可能实现完全不同的内容。
好的,现在哪一个更好,当然取决于您想要实现什么。如果您正在处理C语言的结构体,则我更喜欢第二个,因为您将不会得到未初始化的值。但请忘记关于memset()或类似函数的任何假设。请查看构造函数。

不,这两个版本至少从C++03开始就可以使用了。OP正在谈论POD,因此语义早于C++11。 - juanchopanza
1
好的,C++11将它们更改为执行新操作(调用接受initializer_list的构造函数),但是在C++11之前,该语法已经有了行为。 - Ben Voigt
@aschepler 我认为我两个方面都覆盖到了,因为我试图给出一个更全面的答案。聚合初始化实际上就是他所寻找的,但这并不等同于他的memset()调用。 - cdonat
@Cheersandhth.-Alf,我的推理不是关于语法,而是关于标准中的定义。仅仅因为它在C++11和C++98中看起来并且大多数行为相同,并不意味着它是相同的。是的,这个语法以前也可用,但它有微妙的不同语义。 - cdonat
1
不好意思,知道D3D11_TEXTURE2D_DESC是POD类型有帮助吗? - Cheers and hth. - Alf
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接