【问题标题】:Brace initialization difference betweein {} and {0} in c++C++ 中 {} 和 {0} 之间的大括号初始化区别
【发布时间】:2016-12-06 22:40:46
【问题描述】:

几年前,我读到使用 {} 和 {0} 初始化 POD 在 c++ 中存在一些细微差别,可能会在代码中引入悲观。

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

虽然我知道 {0} 肯定是从 c 继承的东西,并且 {} 是在 c++11 中引入的东西,但它们都应该在编译期间被翻译成同一个 memset() 调用:

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

然而,两种大括号初始化样式中的一种在内存初始化未对齐的情况下做了一些事情,有没有人想知道哪种样式更好以及为什么?

【问题讨论】:

  • 在你继续前进之前,请跳到 Godbolt,亲自看看这些东西究竟做了什么。随意设置测试结构而不是 D3D11_TEXTURE2D_DESC。
  • {} 的使用至少从 C++03 开始​​就存在了。
  • 如果要初始化的零值多于变量,您将获得诊断信息。如果您的零较少,编译器会将其视为有足够的零来初始化所有成员。
  • 我投票决定将此问题作为离题结束,因为它要求根据广泛的提示和关联猜测您可能遇到的问题。

标签: c++ c++11 compilation


【解决方案1】:

您引用的语法称为aggregate initialization

如果初始化子句的数量小于成员数或初始化列表完全为空,则对剩余成员进行值初始化

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

甚至在 C++11 之前就是这种情况——空的初始化列表不是它引入的东西。从 C++11 开始,非 POD 也允许使用该语法。聚合初始化现在是这个新列表初始化的一个特例。

【讨论】:

  • 但是{}是默认聚合初始化,{0}是零聚合初始化。
  • @Nikos 没有“默认聚合初始化”或“零聚合初始化”之类的东西。给定一个聚合,这两种语法都是聚合初始化。 {} 没有任何成员的初始化程序,因此所有成员都进行了值初始化,而 {0} 具有第一个成员的初始化程序,该成员是从字面量 0 复制初始化的,其余成员是值初始化的。从字面量 0 进行复制初始化和值初始化都具有与零初始化相同的行为。
  • "对于第一个成员" 我认为它适用于所有成员,不是吗? {0} 只是将class/struct 中的所有内容初始化为0,不是吗?而{} 只是执行默认的初始化/构造。我错了吗?
  • @Nikos {0} 中的 0 是第一个成员的初始化器。 {0, 0} 将初始化两个成员。 {1} 会将第一个成员初始化为 1。其余没有初始化器的成员被初始化值。对于基本类型,它是零初始化。 {} 没有任何成员的初始化器,因此所有成员都被初始化(在基本类型的情况下初始化为零)。
【解决方案2】:

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

如果你有隐式声明的默认构造函数,它只会为struct 的每个元素调用默认构造函数。内置类型的默认构造函数什么都不做,所以内存不会被设置为零。

对于那些structs,没有定义构造函数,只有公共成员,还有更多限制,归结为C structs,你也得到aggregate initialization。这基本上就是您对 C 的期望。无论如何,D3D11_TEXTURE2D_DESC dsd2 = { 0 }; 不等于 memset(&dsd, 0, sizeof(dsd));,因为编译器可能会出于任何原因向类添加填充,当然,字段的类型可能会完全实现某些东西构造函数不同。

好的,现在哪个更好,当然取决于您要达到的目标。如果您正在处理 C structs,我更喜欢第二个,因为您不会得到未初始化的值。但请忘记任何关于memset() 或类似的假设。请查看构造函数。

【讨论】:

  • 不,至少从 C++03 开始​​,这两个版本都可用。 OP 正在谈论 POD,所以即使是语义也早于 C++11。
  • 好吧,C++11 改变了它们来做一些新的事情(调用接受 initializer_list 的构造函数)但是这种语法在 C++11 之前就有行为
  • OP 指定他在谈论 POD 初始化,所以构造函数不在图片中。
  • @aschepler 我想,我都涵盖了,因为我试图给出一个更全面的答案。聚合初始化实际上是他正在寻找的,但这并不等同于他的memset() 调用。
  • 没有。对不起。知道D3D11_TEXTURE2D_DESC 是 POD 类型是否有帮助?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-08
  • 1970-01-01
  • 2013-12-02
  • 1970-01-01
相关资源
最近更新 更多