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

问题描述 投票:0回答:3

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

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

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

int myArray[10] = {};

此外,类成员

m_array
显然需要初始化,因为默认初始化的整数只会留下随机垃圾,如here所述。

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

带括号:

public:
    X()
    : m_array()
    {}

带牙套:

public:
    X()
    : m_array{}
    {}

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

c++ initialization array-initialization ctor-initializer
3个回答
20
投票

使用

()
初始化任何成员都会执行值初始化。

使用默认构造函数初始化任何类类型,并使用

{}
执行值初始化。

使用

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

使用

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

使用

{}
初始化任何其他类型都会执行值初始化。

因此,对于几乎所有类型,从

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


16
投票

public: X() : m_array() {}

由于括号之间的
表达式列表

为空,因此会发生值初始化。同样适用于: public: X() : m_array{} {}

发生
list 初始化,并且随后进行值初始化,因为 
brace-init-list

为空。

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

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

就是您所说的垃圾值。

  1. T

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

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

  2. 值初始化

    T类型的对象意味着:

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

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

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

  3. 初始化器的语义如下。 ... — 如果初始化器是(非括号)
  4. braced-init-list

    ,则对象或引用是列表初始化的 (8.5.4)。 — 如果初始化器是 (),则该对象是值初始化的。

到目前为止,很明显,值初始化将使数组的每个元素为零,因为
int

不是类类型。但我们还没有讨论列表初始化和聚合初始化,因为数组是聚合。


§8.5.4:

  1. T

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

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

回到§8.5.1:

如果列表中的
    initializer-clauses
  1. 少于那里 是聚合中的成员,那么每个成员都没有明确表示 初始化应从其 brace-or-equal-initializer 初始化 或者,如果没有 brace-or-equal-initializer,则从空的 初始化列表 (8.5.4).
我们再次以 §8.5.4 结束:

  1. T

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

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

由于遍历(草案)标准会让你喘不过气来,我推荐
cppreference

,因为它很好地分解了它。 相关链接:

cpp参考:

  • 聚合初始化

  • 值初始化

  • 标准草案:

    N4140

-1
投票

© www.soinside.com 2019 - 2024. All rights reserved.