我有一个带有数组成员的类,我想将其初始化为全零。
class X
{
private:
int m_array[10];
};
对于局部变量,有一种简单的方法进行零初始化(参见here):
int myArray[10] = {};
此外,类成员
m_array
显然需要初始化,因为默认初始化的整数只会留下随机垃圾,如here所述。
但是,我可以看到对成员数组执行此操作的两种方法:
带括号:
public:
X()
: m_array()
{}
带牙套:
public:
X()
: m_array{}
{}
两者都正确吗? C++11中两者有什么区别吗?
使用
()
初始化任何成员都会执行值初始化。
使用默认构造函数初始化任何类类型,并使用
{}
执行值初始化。
使用
{}
初始化任何其他聚合类型(包括数组)会执行列表初始化,相当于使用 {}
初始化聚合的每个成员。
使用
{}
初始化任何引用类型都会构造一个临时对象,该对象从 {}
初始化,并将引用绑定到该临时对象。
使用
{}
初始化任何其他类型都会执行值初始化。
因此,对于几乎所有类型,从
{}
进行初始化将给出与值初始化相同的结果。您不能拥有引用数组,因此这些也不例外。您“可能”能够在没有默认构造函数的情况下构造聚合类类型的数组,但编译器对于确切的规则并不一致。但回到你的问题,所有这些极端情况对你来说并不重要:对于你的特定数组元素类型,它们具有完全相同的效果。
public:
X()
: m_array()
{}
由于括号之间的表达式列表
为空,因此会发生值初始化。同样适用于:
public:
X()
: m_array{}
{}
list 初始化,并且随后进行值初始化,因为brace-init-list
为空。
为了给出更全面的答案,让我们看一下 N4140 的第 8.5 节。
如果没有为对象指定初始值设定项,则该对象为 默认初始化。当使用自动或自动存储对象时 获得动态存储持续时间,该对象具有不确定值不确定的 value
这个- ,如果没有对该对象执行初始化,则 对象保留不确定的值,直到该值被替换 (5.17).
就是您所说的垃圾值。
对
到目前为止,很明显,值初始化将使数组的每个元素为零,因为- 要
T
类型的对象或引用进行零初始化意味着:
— 如果 T 是数组类型,则每个元素都初始化为零
- 值初始化
初始化器的语义如下。 ... — 如果初始化器是(非括号)
T
类型的对象意味着:— 如果 T 是一个(可能是 cv 限定的)类类型……那么该对象将被默认初始化; ...— 如果 T 是数组类型,则每个元素都是值初始化的;
—否则,该对象将被零初始化。
- braced-init-list
,则对象或引用是列表初始化的 (8.5.4)。 — 如果初始化器是 (),则该对象是值初始化的。
int
不是类类型。但我们还没有讨论列表初始化和聚合初始化,因为数组是聚合。
§8.5.4:
回到§8.5.1:
T
类型的对象或引用的列表初始化定义如下:
— 如果 T 是聚合,则执行聚合初始化 (8.5.1)。
如果列表中的initializer-clauses
我们再次以 §8.5.4 结束:- 少于那里 是聚合中的成员,那么每个成员都没有明确表示 初始化应从其 brace-or-equal-initializer 初始化 或者,如果没有 brace-or-equal-initializer,则从空的 初始化列表 (8.5.4).
cppreference由于遍历(草案)标准会让你喘不过气来,我推荐
T
类型的对象或引用的列表初始化定义如下:
— 否则,如果初始值设定项列表没有元素,则该对象将被值初始化。