我有一个带有数组成员的类,我想将其初始化为全零。
class X
{
private:
int m_array[10];
};
对于局部变量,有一种直接的零初始化方法(参见here):
int myArray[10] = {};
此外,类成员m_array
显然需要初始化,因为默认初始化的int将只留下随机垃圾,如here所述。
但是,我可以看到两种方法为成员数组执行此操作:
括号:
public:
X()
: m_array()
{}
括号:
public:
X()
: m_array{}
{}
两者都正确吗?这两者在C ++ 11中有什么区别吗?
答案 0 :(得分:15)
使用()
初始化任何成员执行值初始化。
使用{}
的默认构造函数初始化任何类类型都会执行值初始化。
使用{}
初始化任何其他聚合类型(包括数组)执行列表初始化,相当于使用{}
初始化每个聚合成员。
使用{}
初始化任何引用类型构造一个临时对象,该对象从{}
初始化,并将引用绑定到该临时对象。
使用{}
初始化任何其他类型执行值初始化。
因此,对于几乎所有类型,{}
的初始化将产生与值初始化相同的结果。您不能拥有引用数组,因此这些不能成为例外。 可能能够在没有默认构造函数的情况下构造聚合类类型的数组,但编译器对确切的规则不一致。但是回到你的问题,所有这些极端情况对你来说并不重要:对于你特定的数组元素类型,它们具有完全相同的效果。
答案 1 :(得分:12)
初始化的类型可能有点繁琐,但在这种情况下它是微不足道的。为:
public:
X()
: m_array()
{}
由于括号之间的表达式列表为空,因此会发生值初始化。同样适用于:
public:
X()
: m_array{}
{}
由于 brace-init-list 为空,列表初始化发生,随后进行值初始化。
为了给出更全面的答案,让我们来看看N4140的§8.5。
- 如果没有为对象指定初始值设定项,则对象为 默认初始化。使用自动或自动存储对象时 获得动态存储持续时间,该对象具有不确定 值,如果没有为对象执行初始化,那么 对象保留不确定的值,直到替换该值 (5.17)。
醇>
这个不确定值就是你所说的垃圾值。
零初始化
T
类型的对象或引用意味着:- 如果T是数组类型,则每个元素都是零初始化
value-initialize
T
类型的对象意味着:- 如果T是(可能是cv限定的)类类型...那么该对象是默认初始化的; ...
- 如果T是数组类型,则每个元素都是值初始化的;
- 否则,该对象为零初始化。
- 醇>
初始值设定项的语义如下。 ... - 如果初始化程序是(非括号) braced-init-list ,则对象或引用是列表初始化的(8.5.4)。
- 如果初始值设定项为(),则对象进行值初始化。
到目前为止,很明显值初始化会使数组的每个元素为零,因为int
不是类类型。但是我们还没有涉及列表初始化和聚合初始化,因为数组是聚合。
§8.5.4:
- 醇>
类型
T
的对象或引用的列表初始化定义如下:- 如果T是聚合,则执行聚合初始化(8.5.1)。
回到§8.5.1:
- 如果列表中的 initializer-clauses 少于那里 是聚合中的成员,然后每个成员不明确 初始化应从其 brace-or-equal-initializer 初始化 或者,如果没有 brace-or-equal-initializer ,则为空 初始化列表(8.5.4)。
醇>
我们再次以§8.5.4结束:
- 醇>
类型
T
的对象或引用的列表初始化定义如下:- 否则,如果初始化列表没有元素,则对象进行值初始化。
由于遍历(草案)标准可能会让你失望,我推荐cppreference因为它打破了它非常好。
cppreference:
标准草案:
答案 2 :(得分:-1)
圆括号在C ++ 98中工作,并且正在调用零初始化,这就是你想要的。我在gcc 4.3上验证过。编辑:删除了关于C ++ 11的错误陈述。我还确认空括号使用clang 3.4和-std = c ++ 11执行空列表初始化。