在 C++ 中,当它们具有依赖项时,我应该如何在初始化列表中强制执行组合对象构造函数的顺序

in C++, how should I enforce the order of composited object constructors in an initializer list when they have dependencies

如果我有一个 class 组合具有相互依赖性的其他对象,我应该(如何)执行它们的构造顺序?

例如

class Parent
{
    Child1 c1;
    Child2 c2;
};

假设 Child2 的构造函数需要一个 Child1&,我想将 c1 传递给 c2 构造函数。

如果我只执行以下操作...

Parent::Parent()
    : c2(c1)
{
}

...这可能不是好事,因为 c2 的初始值设定项为 运行 时 c1 可能尚未构造?或者在 class 声明中 c1 出现在 c2 之前是否足够好?

或者我应该显式地引用 c1 构造函数(如果这不是必需的,那么这样做以使其显式化是一个好习惯吗?)。例如

class Parent
{
    Child1 c1;
    Child2 c2;
};

Parent::Parent()
    : c1()
    : c2(c1)
{
}

这一切都没有效果。成员变量按照声明的顺序构造。句号。

这是来自 cppreference 的完整解释:

The order of member initializers in the list is irrelevant: the actual order of initialization is as follows:

  1. List item If the constructor is for the most-derived class, virtual base classes are initialized in the order in which they appear in depth-first left-to-right traversal of the base class declarations (left-to-right refers to the appearance in base-specifier lists)
  2. Then, direct base classes are initialized in left-to-right order as they appear in this class's base-specifier list
  3. Then, non-static data members are initialized in order of declaration in the class definition.
  4. Finally, the body of the constructor is executed

成员总是按照声明的顺序构造。所以如果你有:

class Parent
{
    Child1 c1;
    Child2 c2;
};

你保证 c1 将在 c2 之前构建。所以,如果 c2 需要一个 Child1&,那么这是完全明确的:

Parent::Parent()
    : c2(c1)
{
}

c1 将被默认构造,然后 c2 将使用一个明确已经构造的 c1 来构造。

class 中的声明顺序是唯一相关的事情。编译器不遵守初始化列表中的构造顺序,实际上您可以启用警告以警告您这一事实(初始化列表中的顺序!=有效构造的顺序)。

在 C++ 中,初始化列表中的成员不是按照您将它们放入列表中的顺序初始化的,而是按照您声明它们的顺序初始化的。事实上,如果你没有按照你声明的顺序初始化成员,g++ 会输出一个警告。因此,您应该注意 声明 成员的逻辑顺序 - 从较低级别到较高级别的对象。

成员数据按声明顺序构造。如果 c1c2 之前声明(就像在您的示例中一样),那么它将首先构造。

但是,您的两个示例之间存在细微差别:

Parent::Parent()
    // c1 is implicitly default-initialized
    : c2(c1)
{
}

Parent::Parent()
    : c1(), //c1 is value-initialized
      c2(c1)
{
}

如果 Child1 是非 POD class 类型,则两者是等价的,否则您将获得 c1.

的不确定值

如果这对您很重要,您可以阅读 default- and value-initialization.

之间的区别