30

我有一个带有数组成员的类,我想将其初始化为全零。

class X
{
private:
    int m_array[10];
};

对于局部变量,有一种简单的零初始化方法(参见此处):

int myArray[10] = {};

此外,m_array显然需要初始化类成员,因为默认初始化 int 只会留下随机垃圾,如此所述。

但是,我可以看到对成员数组执行此操作的两种方法:

带括号:

public:
    X()
    : m_array()
    {}

带大括号:

public:
    X()
    : m_array{}
    {}

两者都正确吗?两者在 C++11 中有什么区别吗?

4

3 回答 3

18

()使用执行值初始化来初始化任何成员。

使用默认构造函数初始化任何类类型并{}执行值初始化。

使用执行列表初始化初始化任何其他聚合类型(包括数组),{}相当于使用 初始化聚合的每个成员{}

用 初始化任何引用类型都会{}构造一个临时对象,该对象从 初始化{},并将引用绑定到该临时对象。

{}使用执行值初始化来初始化任何其他类型。

因此,对于几乎所有类型,初始化 from{}将给出与值初始化相同的结果。你不能有引用数组,所以这些不能是例外。您可能能够在没有默认构造函数的情况下构造聚合类类型的数组,但编译器在确切规则上并不一致。但是回到您的问题,所有这些极端情况对您来说并不重要:对于您的特定数组元素类型,它们具有完全相同的效果。

于 2014-12-09T19:29:14.437 回答
14

初始化的类型可能有点乏味,但在这种情况下它是微不足道的。为了:

public:
    X()
    : m_array()
    {}

由于括号之间的表达式列表为空,因此会发生值初始化。同样适用于:

public:
    X()
    : m_array{}
    {}

由于大括号初始化列表为空,因此发生列表初始化,随后进行值初始化。


为了给出更全面的答案,让我们看一下 N4140 的 §8.5。

  1. 如果没有为对象指定初始化程序,则该对象是默认初始化的。当获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定的值,如果没有对该对象执行初始化,则该对象将保留一个不确定的值,直到该值被替换(5.17)。

这个不确定的值就是你所说的垃圾值。

  1. 对类型的对象或引用进行零初始化T意味着:

    — 如果 T 是数组类型,则每个元素都初始化为零

  2. 对类型对象进行值初始化T意味着:

    — 如果 T 是(可能是 cv 限定的)类类型……那么对象是默认初始化的;...

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

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

  3. 初始化器的语义如下。... - 如果初始化程序是(非括号)大括号初始化列表,则对象或引用是列表初始化的(8.5.4)。

    — 如果初始值设定项是 (),则对象是值初始化的。

到目前为止,很明显值初始化将使数组的每个元素都为零,因为int它不是类类型。但是我们还没有讨论列表初始化和聚合初始化,因为数组是一个聚合。

§8.5.4:

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

    — 如果 T 是一个聚合,则执行聚合初始化 (8.5.1)。

回到§8.5.1:

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

我们再次以 §8.5.4 结束:

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

    — 否则,如果初始化列表没有元素,则对象被值初始化。

由于遍历(草案)标准会让你喘不过气来,我推荐cppreference因为它很好地分解了它。

相关链接:

cpp参考:

标准草案:

于 2014-12-09T20:37:25.983 回答
-1

括号在 C++98 中工作,并要求零初始化,这正是你想要的。我在 gcc 4.3 上进行了验证。编辑:删除了关于 C++11 的错误陈述。我还确认空大括号使用带有 -std=c++11 的 clang 3.4 执行空列表初始化。

于 2014-12-09T15:46:48.820 回答