在C++中,如何确保在另一个对象之前构造一个对象?

use*_*472 2 c++ constructor class object

在C++中,我们有两个全局对象,它们都由不同文件中的其他对象定义.一个物体的构造取决于已经构建的另一个物体.

class independent; 
class  dependent;
independent o1;
dependent o2;
Run Code Online (Sandbox Code Playgroud)

为了确保在o2之前构造o1,我可以通过在o2之前声明o1来实现.

这可以确保o1是在o2之前建造的吗?如果编译器改变了odering怎么办?

谢谢

Jul*_*ult 8

C++标准保证在同一编译单元中初始化静态变量,但在单独的编译单元中未定义顺序.这通常被称为"静态初始化顺序惨败".

因此,如果您的变量在同一个.cpp中声明,它们会按照您声明的顺序进行初始化,如果它们位于不同的文件中,您根本就不知道(我已经看到非常激进的链接优化的情况)这改变了静态变量初始化的顺序,无论情况如何,但这不符合标准,并且不应该在正常使用情况下发生).

核心问题

你的问题背后隐藏着一个设计问题.

  1. 如果你的一个类依赖于另一个类,那么它的结构应该明确地显示这个依赖关系,并且不可能进入不满足依赖性的情况.

  2. 如果你有一个全局对象依赖于你无法控制的另一个全局对象,那么从属对象可能不应该是全局对象.

您的问题没有提供足够的详细信息来了解哪种设计最适合您,因此这里有一些您可以做出决定的建议.

依赖

首先,让我们表达这种依赖......

初始化时间依赖性

类的实例dependent需要一个independent初始化对象,但以后不再需要它.然后只是使默认构造函数不可访问并定义自己的构造函数.

class dependent
{
  private:
    dependent(); // Implementation is optional

  public:
    dependent(const independent& sister)
    {
      // Initialize stuff
    }
}
Run Code Online (Sandbox Code Playgroud)

终身依赖

类的实例在其生命周期中dependent需要一个对象,independent否则就没有意义.然后定义一个成员,该成员是对另一个对象的引用,并再次使默认构造函数不可访问并定义您自己的构造函数.

class dependent
{
  private:
    dependent(); // No implementation

  public:
    dependent(const independent& sister): m_sister(sister)
    {
      // Initialize stuff
    }

    const independent& GetSister() const { return m_sister; }
    void SetSister(const independent& sister) { m_sister = sister; }

  private:
    const independent& m_sister;
}
Run Code Online (Sandbox Code Playgroud)

失去依赖

类的实例dependent可能需要一个independent工作的对象,但仍然有理由不拥有一个.然后定义一个成员,该成员是指向另一个对象的指针.

class dependent
{
  public:
    dependent()
    {
      // Initialize stuff
    }

    const independent* GetSister() const { return m_sister; }
    void SetSister(const independent* sister) { m_sister = sister; }

  private:
    const independent* m_sister;
}
Run Code Online (Sandbox Code Playgroud)

初始化顺序

现在让我们确保independent对象准备就绪dependent.

初始化功能

你可以使用指针和Init()函数.

Independent* sister = NULL;
Dependent* brother = NULL;

Init()
{
    assert(brother == NULL && sister == NULL);
    sister = new independent();
    brother = new dependent(sister);
}
Run Code Online (Sandbox Code Playgroud)

使用时创建

您可以在函数中使用静态变量来强制执行创建顺序.这有效,但是让几个类的实例变得很麻烦.

independent& GetSister()
{
    static independent sister; // Initialized on first use
    return sister;
}

dependent& GetBrother()
{
    static dependent brother(GetSister()); // Initialized on first use
    return brother;
}
Run Code Online (Sandbox Code Playgroud)

没有全局变量

最后,最干净的方法可能是试图完全摆脱全局变量.然后,您将使用局部变量(您可以完全控制创建顺序).当然你必须通过需要它们的函数传递它,如果有很多它们,它会变得很麻烦.

但是当你确定需要这些对象的所有代码时,在对象中移动它可能是有意义的,并且你的两个原始全局变量将简单地成为该对象的成员.

class Foo
{
  public:
    Foo(): m_sister(...), m_brother(...)
    {
       // Initialize stuff
    }

    // Functions using the objects go here

  private:
    independent m_sister;
    dependent m_brother;
}
Run Code Online (Sandbox Code Playgroud)

结论

嗯,我意识到我的答案很长,我有点沮丧.这是外卖:

  • 尽可能避免全局变量.
  • 表达类之间的依赖关系.
  • 如果让事情变得更容易,请不要犹豫将代码和状态变量封装成类,最终会有意义.


Meh*_*dad 8

简单:如果A依赖于B那么A应该B在其构造函数中作为参数.

不要让你的代码骗你.


Cor*_*ica 6

如果在编译单元中有两个全局变量,那么它们将按顺序初始化.如果它们在不同的编译单元中处于不同的顺序(就像它们在由不同的.cpp包含在不同顺序中的不同.h文件中),则结果是未定义的.

如果您必须按顺序排列它们,但无法将它们放在同一个补偿单元中,请考虑使用单例模式.

class Independent
{
    public:
        static Independent& getO1()
        {
            static Independent o1;
            return o1;
        }
};

class Dependent
{
    public:
        static Dependent& getO2()
        {
            Independent::getO1(); // force o1 to exist first
            static Dependent o2;
            return o2;
        }
};
Run Code Online (Sandbox Code Playgroud)

这使用静态局部变量在首次使用时初始化的规则,以确保顺序,无论.h文件如何包含在内.