【问题标题】:Meaning of default initialization changed in C++11?在 C++11 中更改了默认初始化的含义?
【发布时间】:2014-04-09 14:24:23
【问题描述】:

C++2003 8.5/5 说:

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

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

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

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

[强调添加。]

C++2011 标准将最后一项更改为

—否则,不执行初始化

对于某些程序来说,这似乎是一个重大变化。这是故意的吗?

编辑

这里有一些代码可以激发这个问题:

class Foo {
  public:
    Foo() : m_values() {}

    int m_values[3];
};

在 C++11 之前,我认为在默认构造函数中明确提及 m_values默认初始化该数组。由于数组的元素是标量,我预计这意味着值都设置为 0。

在 C++11 中,似乎不再保证会发生这种情况。但是,正如 Mooing Duck 在 cmets 中指出的那样,也许这不再是默认初始化的情况,而是保留了预期行为的其他形式。欢迎引用。

【问题讨论】:

  • 对象未初始化。所以,它们是未初始化的对象。
  • @Victor:他知道。他的观点是,从初始化到未初始化的变化是一个突破性的变化。
  • 我记得听说 C++03 没有“值初始化”、“默认初始化”和“零初始化”之类的。是否有可能以前默认初始化的东西现在初始化为零,这使得这成为一个不破坏性的变化?
  • m_values 应该是值初始化的,因为它是带有空括号的成员初始化器列表的一部分。

标签: c++ c++11 initialization language-lawyer c++-faq


【解决方案1】:

严格来说,default-initialize的定义已经从C++03变成了C++11。但是还必须考虑到对象_default-initialize_d 的情况发生了变化:

§8.5p9 C++03 状态:

如果没有为对象指定初始化器,并且对象是(可能是 cv 限定的)非 POD 类类型(或其数组),则该对象应默认初始化;如果对象是 const 限定类型,则基础类类型应具有用户声明的默认构造函数。否则,如果没有为非静态对象指定初始化器,则该对象及其子对象(如果有)具有不确定的初始值;如果对象或其任何子对象是 const 限定类型,则程序是非良构的。

§8.5p11 C++11 状态:

如果没有为对象指定初始化器,则该对象是默认初始化的;如果不进行初始化,则具有自动或动态存储期限的对象具有不确定的值。

正如@JamesKanze 已经指出的那样,default-initialization 在 C++03 中执行,当没有为非 POD 类类型的对象指定初始化程序时。在 C++11 中,如果没有指定初始化器,则对象(任意类型)是 默认初始化。由于这一变化,default-initialize 的定义也必须更改,以便与 C++03 兼容。


您的示例与 default-initialization 无关。初始化器是一组空括号的对象总是值初始化

【讨论】:

    【解决方案2】:

    根据cppreference.com(因为它使用比标准更友好的语言):

    默认初始化在三种情况下执行:

    3) 当基类或非静态数据成员未在 构造函数初始化器列表并调用该构造函数。

    值初始化在三种情况下进行:

    3,7) 初始化非静态数据成员或基类时 使用带有一对空括号or braces (since C++11)的成员初始化程序@

    请注意,C++11 部分属于or braces,而不是整个段落。

    还有:

    对 T 类型的对象进行值初始化意味着:
    — 如果 T 是数组类型,则每个元素都是值初始化的;
    — 否则,对象被零初始化

    所以在 C++11 中 default-initialization 不会对成员进行零初始化,但 value-initialization 会。

    【讨论】:

      【解决方案3】:

      最终效果几乎相同。在 C++03 中,default-initialize 的使用仅限于非 POD 类类型,因此最后一点从未应用。在 C++11 中,该标准通过消除使用默认初始化的条件来简化措辞,并更改默认初始化的定义以涵盖所有情况,以对应之前发生的情况。

      【讨论】:

      • 具体来说,C++03 8.5/9:如果没有为对象指定初始化器,并且该对象是(可能是 cv 限定的)非 POD 类类型(或其数组),则对象应默认初始化;如果对象是 const 限定类型,则基础类类型应具有用户声明的默认构造函数。否则,如果没有为非静态对象指定初始化器,则该对象及其子对象(如果有)具有不确定的初始值;如果对象或其任何子对象是 const 限定类型,则程序格式错误。
      • 对比C++11 8.5/11:如果没有为对象指定初始化器,则对象默认初始化;如果不执行初始化,则具有自动或动态存储持续时间的对象具有不确定的值。
      • 我不太明白这个答案。您是说因为示例中的 m_values 数组是 POD,因此默认初始化从未应用,即使在 C++03 中也不适用?你能澄清一下吗?如果我构造一个Foo如上图,m_values中的值是0还是不确定?
      • @JamesKanze:你的回答看起来对很多人都有帮助,但我仍然有我之前评论的问题。如果你能澄清这些,我很乐意接受。
      • @AdrianMcCarthy:由于构造函数中明确的m_values(),因此在任何版本的C++ 中都不会默认初始化数组;它是值初始化的(在 C++03 和 11 中相同)。如果不存在,则数组在 C++03 中未初始化,在 C++11 中默认初始化。
      猜你喜欢
      • 2020-02-08
      • 2016-03-27
      • 1970-01-01
      • 1970-01-01
      • 2017-11-21
      • 2014-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多