C++标准保证同一编译单元内静态变量的顺序初始化,但在不同的编译单元中顺序是未定义的。这通常被称为“静态初始化顺序问题”。因此,如果你的变量在同一个.cpp文件中声明,它们将按照你声明它们的顺序进行初始化,如果它们在不同的文件中,则根本不知道顺序(我见过非常激进的链接优化情况,它们无论何时都会更改静态变量初始化的顺序,而不考虑情况,但这不符合标准,并且在正常使用情况下不应该发生)。
核心问题:你的问题背后存在设计问题。如果一个类依赖于另一个类,则其结构应明确显示此依赖关系,并使得不可能出现未满足依赖关系的情况。如果你有一个全局对象依赖于另一个对象,但你对其没有明确的控制,则可能不应使它成为全局对象。由于你的问题没有提供足够的细节来了解哪种设计最适合你,因此以下是一些建议,供你做出决策。
依赖:首先,让我们表达这种依赖关系...
初始化时间依赖性:类dependent的一个实例需要一个independent对象进行初始化,但后来不再需要。那么只需使默认构造函数无法访问并定义你自己的构造函数即可。
class dependent
{
private:
dependent();
public:
dependent(const independent& sister)
{
}
}
终身依赖
dependent
类的实例在其整个生命周期中需要 independent
对象才有意义。因此,需要定义一个成员变量引用另一个对象,并且将默认构造函数设为不可访问,并定义自己的构造函数。
class dependent
{
private:
dependent();
public:
dependent(const independent& sister): m_sister(sister)
{
}
const independent& GetSister() const { return m_sister; }
void SetSister(const independent& sister) { m_sister = sister; }
private:
const independent& m_sister;
}
消除依赖关系
类dependent
的实例可能需要一个independent
对象来工作,但是不一定非得有一个。可以定义一个成员指针指向另一个对象。
class dependent
{
public:
dependent()
{
}
const independent* GetSister() const { return m_sister; }
void SetSister(const independent* sister) { m_sister = sister; }
private:
const independent* m_sister;
}
初始化顺序
现在让我们确保在依赖对象准备好时,independent
对象也已经准备就绪。
初始化函数
您可以使用指针和一个 Init()
函数。
Independent* sister = NULL;
Dependent* brother = NULL;
Init()
{
assert(brother == NULL && sister == NULL);
sister = new independent();
brother = new dependent(sister);
}
按需创建
您可以在函数中使用静态变量来强制创建的顺序。这样做虽然可行,但如果需要多个类的实例就会变得很麻烦。
independent& GetSister()
{
static independent sister;
return sister;
}
dependent& GetBrother()
{
static dependent brother(GetSister());
return brother;
}
避免使用全局变量
最后,最干净的方法可能是尽量摆脱全局变量。相反,你应该使用本地变量(你完全掌控它们的创建顺序)。当然,你需要将它们传递给需要它们的函数,如果有很多这样的函数,那么这会变得繁琐。
但是,当你确定所有需要这些对象的代码时,将其移动到一个对象中可能是有意义的,你最初的两个全局变量只需成为该对象的成员即可。
class Foo
{
public:
Foo(): m_sister(...), m_brother(...)
{
}
private:
independent m_sister;
dependent m_brother;
}
结论
嗯,我意识到我的回答有点长了,有点过头了。这是重点:
- 尽可能避免使用全局变量。
- 表达类之间的依赖关系。
- 如果封装代码和状态变量能够使事情变得更加容易,请不要犹豫,将其封装到一个类中,这最终是有意义的。