16

我昨天才知道,为初始化列表项指定参数是可选的。但是,在这种情况下发生的事情的规则是什么?

在下面的示例中,ptr 是否会被初始化为 0、切换为 false 和 Bar 默认构造?我想这个问题有点多余,因为如果未指定的参数值 == 未定义的行为,初始化列表中将没有什么意义。

我是否也可以指出 C++ 标准的部分,该部分说明了在初始化列表项没有被赋予参数的情况下的行为?

class Bar
{
    Bar() { }
};

class SomeClass;
class AnotherClass
{
public:
    SomeClass *ptr;
    bool toggle;
    Bar bar;

    AnotherClass() : ptr(), toggle(), bar() { }
    // as opposed to...
    // AnotherClass() : ptr(NULL), toggle(false), bar(Bar()) { }
};
4

3 回答 3

14

是的,成员将分别初始化为零和默认构造的对象。

C++ 11 标准在 12.6.2/7 中指定了这种行为:

mem-initializer 中的 expression-list 或 braced-init-list 用于根据 8.5 的直接初始化规则初始化指定的子对象(或者,在委托构造函数的情况下,完整的类对象)。

反过来,8.5/10 内容如下:

初始值设定项为空括号集的对象,即 (),应进行值初始化。

第 8.5/7 段定义了value-initialized

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

  • 如果 T 是具有用户提供的构造函数(12.1)的(可能是 cv 限定的)类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化格式错误) ;
  • 如果 T 是没有用户提供的构造函数的(可能是 cv 限定的)非联合类类型,则该对象被零初始化,并且如果 T 的隐式声明的默认构造函数不平凡,则调用该构造函数。
  • 如果 T 是一个数组类型,那么每个元素都是值初始化的;
  • 否则,对象被零初始化。

最后,8.5/5 定义了zero-initialized

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

  • 如果 T 是标量类型(3.9),则将对象设置为值 0(零),作为整数常量表达式,转换为 T;
  • 如果 T 是(可能是 cv 限定的)非联合类类型,则每个非静态数据成员和每个基类子对象都被初始化为零并且填充被初始化为零位;
  • 如果 T 是(可能是 cv 限定的)联合类型,则对象的第一个非静态命名数据成员被零初始化,填充被初始化为零位;
  • 如果 T 是数组类型,则每个元素都初始化为零;
  • 如果 T 是引用类型,则不执行初始化。
于 2013-01-10T14:07:26.363 回答
6

在下面的示例中,ptr 是否会被初始化为 0、切换为 false 和 Bar 默认构造?

是的。如果成员初始化器出现在带有空括号的初始化器列表中,则该成员是value initialized。这意味着数值类型将被初始化为零、指向 null 的指针以及具有使用该构造函数的默认构造函数的类。

如果您根本不将成员包含在初始化列表中,那么它将被默认初始化;在这种情况下。数字和指针类型将保持未初始化。

我是否也可以指出 C++ 标准的部分,该部分说明了在初始化列表项没有被赋予参数的情况下的行为?

C++11 12.6.2/7 指定规则与直接初始化相同。

C++11 8.5/16 指定如果初始化程序是(),则对象是值初始化的。

C++11 8.5/7 定义了值初始化。

于 2013-01-10T14:07:57.323 回答
2

[dcl.init] (aka 8.5) 中介绍了初始化

第 10 点说:

初始值设定项为空括号集的对象,即 (),应进行值初始化。

简单地说,值初始化是类的默认构造和非类类型的零初始化。

于 2013-01-10T14:07:06.920 回答