我有一个带有数组成员的类,我想将其初始化为全零。
class X
{
private:
int m_array[10];
};
对于局部变量,有一个简单的零初始化方法(见这里(:
int myArray[10] = {};
此外,类成员显然需要初始化m_array
,因为默认初始化整数只会留下随机垃圾,如此处所述。
但是,我可以看到对成员数组执行此操作的两种方法:
带括号:
public:
X()
: m_array()
{}
带牙套:
public:
X()
: m_array{}
{}
两者都正确吗?C++11 中两者有什么区别吗?
使用 ()
初始化任何成员都会执行值初始化。
使用 {}
的默认构造函数初始化任何类类型都会执行值初始化。
{}
初始化任何其他聚合类型(包括数组(将执行列表初始化,等效于 使用 {}
初始化聚合的每个成员。
使用 {}
初始化任何引用类型都会构造一个临时对象,该对象从 {}
初始化,并将引用绑定到该临时对象。
使用 {}
初始化任何其他类型将执行值初始化。
因此,对于几乎所有类型,从 {}
初始化将给出与值初始化相同的结果。您不能有引用数组,因此这些数组不能例外。您可能能够在没有默认构造函数的情况下构造聚合类类型的数组,但编译器在确切的规则上并不一致。但是回到你的问题,所有这些极端情况对你来说并不重要:对于你的特定数组元素类型,它们具有完全相同的效果。
初始化的类型可能有点乏味,但在这种情况下,它是微不足道的。为:
public:
X()
: m_array()
{}
由于括号之间的表达式列表为空,因此会发生值初始化。同样适用于:
public:
X()
: m_array{}
{}
发生列表初始化,随后进行值初始化,因为大括号初始化列表为空。
<小时 />为了给出更全面的答案,让我们来看看 N8.5 的 §4140。
如果未为对象
- 指定初始值设定项,则该对象为 默认初始化。当存储对象时具有自动或 得到动态存储持续时间,对象具有不确定 值,如果未对对象执行初始化,则 对象保留不确定值,直到该值被替换 (5.17(。
此不确定值就是您所说的垃圾值。
将
T
类型的对象或引用零初始化意味着:— 如果 T 是数组类型,则每个元素都是零初始化的
对类型为
T
的对象进行值初始化意味着:— 如果 T 是(可能符合 CV 条件的(类类型......然后对象默认初始化;...
— 如果 T 是数组类型,则每个元素都是值初始化的;
— 否则,对象初始化为零。
初始值设定项的语义如下。 — 如果初始值设定项是(非括号(大括号初始化列表,则对象或引用是列表初始化的 (8.5.4(。
— 如果初始值设定项为 ((,则对象为值初始化。
到目前为止,很明显,值初始化将使数组的每个元素为零int
因为不是类类型。但是我们还没有介绍列表初始化和聚合初始化,因为数组是一个聚合。
§8.5.4:
类型为
T
的对象或引用的列表初始化定义如下:— 如果 T 是聚合,则执行聚合初始化 (8.5.1(。
回到 §8.5.1:
- 如果列表中的初始值设定项子句少于 是聚合中的成员,则每个成员未显式 初始化应从其大括号或等于初始值设定项初始化 或者,如果没有大括号或等于初始值设定项,则从空 初始值设定项列表 (8.5.4(。
我们再次以 §8.5.4 结尾:
T
类型的对象或引用的列表初始化定义如下:— 否则,如果初始值设定项列表没有元素,则对象将被值初始化。
由于遍历(草案(标准可以让你喘口气,我推荐 cpp偏好,因为它分解得很好。
相关链接:
CPP 首选项:
聚合初始化
值初始化
标准草案:
- N4140
C++98 中工作,并且要求零初始化,这是您想要的。我在 gcc 4.3 上进行了验证。编辑:删除了关于 C++11 的错误陈述。我还确认空大括号使用 clang 3.4 和 -std=c++11 执行空列表初始化。