【问题标题】:Difference between default-initialize and value-initialize in C++03?C++03中默认初始化和值初始化的区别?
【发布时间】:2011-10-28 10:17:26
【问题描述】:

我一直认为创建一个新对象总是会调用一个对象的默认构造函数,而构造函数是显式的还是编译器自动生成的并没有区别。根据this highly regarded answer 的另一个问题,这在 C++98 和 C++03 之间发生了微妙的变化,现在像这样工作:

struct B { ~B(); int m; }; // non-POD, compiler generated default ctor 
new B;   // default-initializes (leaves B::m uninitialized)
new B(); // value-initializes B which zero-initializes all fields since its default ctor is compiler generated as opposed to user-defined.

谁能告诉我:

  1. 为什么要更改标准,即这有什么好处,或者现在有什么以前没有的可能;
  2. “默认初始化”和“值初始化”这两个术语究竟代表什么?
  3. 标准的相关部分是什么?

【问题讨论】:

  • 新 C++11 标准的相关部分是 8.5(“Initializers”)第 5,6,7 条。
  • 也许它让人们可以选择是否使用默认 ctor。在旧版本的 C++ 中,当没有参数时,括号通常会被忽略。因此,在新选项上加上括号将影响较少的遗留代码。
  • 我不会称之为改变,而是更正。它至少在例如上下文中是有意义的。 std::map 其中由 [] 创建的值是值初始化的,例如std::map 所有 U* 都初始化为 0
  • @PlasmaHH,我想我得到了一个灯泡时刻 - 你是说在 C++03 之前,POD 类型将不会被初始化,即使用()?我确信在特定的std::map 情况下std::pair<A,B>() 可以显式调用AB 的构造函数。
  • @Mark Ransom: acceleratedcpp.com/authors/koenig/c++std/revisions.pdf 包含 98 和 03 之间差异的非正式列表。在 8.5 左右的更改中,主要区别在于对于没有用户定义 ctor 的非 pod,子对象以前不是初始化,因为 () 是默认初始化,它调用了默认 ctor,它什么也没做。现在 () 是值初始化,当没有用户定义的 ctor 时,它将对所有子对象进行值初始化。由于pair不是POD,默认initd时总是调用A()和B(),所以这里的关键是当B()是非POD且没有用户de

标签: c++ standards default-value default-constructor


【解决方案1】:

我不知道更改的基本原理(或之前的标准是怎样的),但关于它是怎样的,基本上 default-initialization 要么调用用户定义的构造函数,要么什么都不做(这里有很多手动操作:这是递归地应用于每个子对象,这意味着具有默认构造函数的子对象将被初始化,没有用户定义的构造函数的子对象将保持未初始化)。

这属于语言的只为你想要的东西付费的理念,并且在所有与 C 兼容的类型中都与 C 兼容。另一方面,您可以请求 value-initialization,这相当于为将其 初始化为 0 的对象调用默认构造函数转换为其余子对象的适当类型。

这在第 8.5 节初始化程序中有所描述,并且导航并非易事。 zero-initializedefault-initializevalue-initialize 的定义是第 5 段:

对 T 类型的对象进行零初始化意味着:

——如果T是标量类型(3.9),则将对象设置为0(零)转换为T的值;

——如果 T 是非联合类类型,则每个非静态数据成员和每个基类子对象都被零初始化;

—如果 T 是联合类型,则对象的第一个命名数据成员 89) 初始化为零;

——如果T是数组类型,每个元素都初始化为零;

——如果 T 是引用类型,则不执行初始化。

默认初始化 T 类型的对象意味着:

——如果 T 是非 POD 类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化是非良构的);

——如果 T 是一个数组类型,每个元素都是默认初始化的;

——否则,对象被零初始化。

对 T 类型的对象进行值初始化意味着:

——如果 T 是具有用户声明的构造函数 (12.1) 的类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化是非良构的);

——如果 T 是没有用户声明的构造函数的非联合类类型,则 T 的每个非静态数据成员和基类组件都是值初始化的;

——如果T是一个数组类型,那么每个元素都是值初始化的;

——否则,对象被零初始化

调用引用类型实体的默认初始化或值初始化的程序是错误的。如果 T 是 cv 限定类型,则 T 的 cv 非限定版本用于这些零初始化、默认初始化和值初始化的定义。

【讨论】:

  • 您的前导段落已将默认初始化的行为定义为使用 ctor 或其左侧未初始化。我的问题是对 8.5 Initializer 部分的包含引用的解释,该部分定义了作为最后一步的 default-initialize ...“-否则,该对象是零初始化的”。它似乎表明,如果没有 ctor,则使用零初始化规则而不是让它未初始化。
  • @CBO:那个特别的引用来自 C++03,在 C++11 中最后一项已更改为:否则,不执行初始化。此时的关键是几段后写的内容。对于没有提供初始化程序的对象,在 C++03 中,该对象未初始化(在 /9 中),在 C++11 中,该对象是 default-initialized (/12)。不确定这是否能解决您的问题
  • 有道理,感谢您的跟进。我建议更新您的帖子,现在包含 C++11 的内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-08
  • 1970-01-01
  • 2014-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-25
相关资源
最近更新 更多