零初始化列表中的数组成员



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

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。

    如果未为对象
  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 类型的对象或引用的列表初始化定义如下:

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

由于遍历(草案(标准可以让你喘口气,我推荐 cpp偏好,因为它分解得很好。

相关链接:

CPP 首选项:

  • 聚合初始化

  • 值初始化

标准草案:

  • N4140
括号在

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

相关内容

  • 没有找到相关文章