如何在C++类的初始化列表中初始化成员结构体?

55

我在C ++中有以下类定义:

struct Foo {
  int x;
  char array[24];
  short* y;
};

class Bar {
  Bar();

  int x;
  Foo foo;
};

我想在Bar类的初始化器中将"foo"结构体(及其所有成员)初始化为零。可以这样做吗:

Bar::Bar()
  : foo(),
    x(8) {
}

在初始化列表中,foo(x) 到底做了什么?

还是说编译器会自动将结构体初始化为零?


4
请注意,在初始化列表中应按声明顺序列出成员,而您先声明了 x,但将其放在了初始化列表的第二个位置。 - Adam Badura
2个回答

55
首先,您应该(必须!)阅读此c++ faq有关POD和聚合体的内容。在您的情况下,Foo确实是一个POD类,而foo()是一个值初始化

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

  • 如果T是带有用户声明构造函数(12.1)的类类型(第9条款),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化无效);
  • 如果T是非联合类类型且没有用户声明构造函数,则T的每个非静态数据成员和基类分量均进行值初始化;
  • 如果T是数组类型,则每个元素都进行值初始化;
  • 否则,对象将进行零初始化
因此,是的,foo将被零初始化。请注意,如果从Bar构造函数中删除此初始化,则foo只会进行默认初始化

如果未为对象指定初始化程序,并且对象是(可能是cv限定的)非POD类类型(或其数组),则对象应进行默认初始化;如果对象是const限定类型,则底层类类型必须具有用户声明的默认构造函数。否则,如果未为非静态对象指定初始化程序,则该对象及其子对象(如果有)具有不确定的初始值。


2
如果foo被定义为const成员会怎样? - RezaPlusPlus

10

在标准的C++中,你需要为Foo创建一个构造函数。

struct Foo {

  Foo(int const a, std::initializer_list<char> const b, short* c)
    : x(a), y(c) {
    assert(b.size() >= 24, "err");
    std::copy(b.begin(), b.begin() + 24, array);
  }

  ~Foo() { delete y; }

  int x;
  char array[24];
  short* y;
};

class Bar {

  Bar() : x(5), foo(5, {'a', 'b', ..., 'y', 'z'},
    new short(5)) { }

  private:

  int x;
  Foo foo;
};

C++0x 中,您可以使用统一初始化列表,但仍需要 Foo 的析构函数:

class Bar {

  Bar() : x(5), foo{5, new char[24]{'a', 'b', ..., 'y', 'z'},
    new short(5)} { }
  ~Bar() { delete[] foo.array; delete foo.y;}
  }
  private:

  int x;
  Foo foo;
};

要进行默认初始化foo(如Bar() : foo(), x(8) { }),您需要为Foo提供一个默认构造函数。


3
在你使用C++03和C++0x时略有不清楚。如果我没记错,initializer_list是C++0x的一部分。另外,在你的第二个代码块中你创建了两个内存泄漏。 - Fabio Fracassi
现在您有一个双重删除(foo.y)和一个内存泄漏(来自new char[24]),此外,我不确定(但我可能在这里错了)这是否是使用initializer_list的方式。 - Fabio Fracassi
有类似的情况,但是 struct Foo {int x,y; }struct Goo : Foo { int z; }struct Boo { Foo fs[2]; int x; } 和静态常量数组 static const Boo boos[] = { {{foo1, foo2},11}, {{foo3, foo6},15} }。在初始化时遇到了困境:像这样 struct Goo(int x, int y) : Foo(x,y),我需要一个 Foo 的构造函数,但不能在初始化列表中使用非聚合体(构造函数)... - slyy2048

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接