以下代码:
class C {
public:
static C& Instance() {
static C c;
return c;
}
~C(){std::cout << "c destructed\n";}
private:
C(){}
};
class D{//similar to C but prints `d destructed` on destruction
//...
int main()
{
auto c = C::Instance();
auto d = D::Instance();
}
//outputs (with gcc)
//d destructed
//c destructed
//d destructed
//c destructed
我有几个问题:
答案 0 :(得分:8)
这个结构的要点是施加施工顺序(因此也就是破坏顺序)。
<强>建筑强>
由于这些是局部静态变量,因此构造顺序取决于第一次调用各自Instance
函数的顺序。
由于这是在main
中完成的,因此完全指定了构造顺序。
使订单未指定的唯一方法是,如果您在不同翻译单元中的静态初始化中使用它们,例如,如果有
C& the_c = C::Instance();
而另一个
D& the_d = D::Instance();
<强>销毁强>
使用静态存储破坏对象与构造顺序相反。
3.6.3,终止,第1段:
如果构造函数完成或动态初始化了 具有静态存储持续时间的对象在之前被排序 另外,对第二个析构函数的完成进行了排序 在第一个析构函数启动之前。
因此,销毁订单完全由施工订单指定。
请注意,即使其中一个构造依赖于另一个构造,也可以很好地指定这个单例构造,而不管翻译单元。
也就是说,这是非常安全的,无论它在何处定义都无关紧要:
class C {
public:
static C& Instance() {
static C c(D::Instance());
return c;
}
~C(){ m_d.doSomething(); } // Yes, this is safe.
private:
C(D& d) : m_d(d) { m_d.doSomething(); } // Yes, this is safe.
D& m_d;
};
答案 1 :(得分:-1)
通常,静态对象的破坏顺序(包括在您的情况下使用的静态局部变量)是未定义的。
为了确保销毁顺序,我使用的一种模式是利用std :: shared_ptr。例如,如果要确保C单例在D单例被销毁之前保持有效,则可以存储shared_ptr&lt; C>在D:
class C {
static shared_ptr<C> Instance() {
static auto c = make_shared<C>();
return c;
}
};
class D {
static shared_ptr<D> Instance() {
static auto d = make_shared<D>();
return d;
}
D(): c_(C::Instance()) {}
private:
shared_ptr<C> c_;
};