19

我正在阅读 C++11 标准,但不知道是否

T x{};

是值初始化或默认初始化(自动存储)。它确实很清楚地说:

10 初始化器为空括号集的对象,即 (),应进行值初始化。

然后

11 如果没有为对象指定初始化器,则该对象是默认初始化的;

但我能找到T x{};的只是:

以 T x(a) 形式发生的初始化;Tx{a}; 以及在 new 表达式 (5.3.4)、static_cast 表达式 (5.2.9)、函数符号类型转换 (5.2.3) 以及基类和成员初始化程序 (12.6.2) 中称为直接初始化。

如果初始值设定项是(无括号的)大括号初始化列表,则对象或引用是列表初始化的(8.5.4)。

我不熟悉阅读标准的水平。有人可以指出我正确的方向吗?

4

2 回答 2

26

您的报价确实涵盖了这一点:

如果初始值设定项是(无括号的)花括号初始化列表,则对象或引用是列表初始化的(8.5.4)。

跳到 8.5.4 列表初始化。在这里,我解释/省略了一些与以下情况无关的点T x{}

类型 T 的对象或引用的列表初始化定义如下:

  • 如果 T 是聚合,则执行聚合初始化 (8.5.1)。
  • 否则,如果初始值设定项列表没有元素并且 T 是具有默认构造函数的类类型,则该对象是值初始化的
  • 否则,如果Tstd::initializer_list<E> [...]
  • 否则,[如果列表不为空且与构造函数匹配]
  • 否则,[如果列表只有一个元素]
  • 否则,[如果T是引用类型]
  • 否则,如果初始化列表没有元素,则对象被值初始化。
  • 否则,程序格式错误。

第一点,聚合初始化也在 C++03 中;在那种情况下T x{};是一样的T x = {};

对于第二点“T是具有默认构造函数的类类型”,它是值初始化的,这意味着调用默认构造函数。

如果T是原始类型,则应用倒数第二个点并再次对其进行值初始化

回到聚合初始化案例,在 8.5.1/7 中有:

如果列表中的初始化子句少于聚合中的成员,则每个未显式初始化的成员都应从其大括号或相等初始化器中初始化,或者,如果没有大括号或相等初始化器,从一个空的初始化列表(8.5.4)。

括号或相等初始化器是指在类定义中内联提供的初始化器。如果它不存在,则它被初始化,就好像该成员已被初始化一样{}(因此,此逻辑递归地应用于每个聚合成员)。

例如,

struct T
{
     int a;
};

然后T x {};导致a被初始化为int a{};,这是值初始化,因为int它是原始类型。

于 2014-09-21T22:02:42.647 回答
8

尽管 Matt McNabb 已经介绍了这一点,但我会补充说,如果您在浏览标准时遇到问题,查看cppreference并没有什么坏处。他们关于列表初始化的部分很好地分解了它。

本质上,就像您的标准报价所说,T x{};指的是:

使用大括号括起来的表达式列表或嵌套列表 ( braced-init-list ) 初始化命名变量。

和:

T 类型对象的列表初始化的效果是:

  • 如果花括号初始化列表为空且 T 是具有默认构造函数的类类型,则执行值初始化。

[...]

  • 否则,如果括号初始化列表没有元素,则 T 是值初始化的。
于 2014-09-21T22:11:04.457 回答