迈耶斯单身人士的破坏秩序

use*_*183 6 c++ language-lawyer

要以下代码:

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
Run Code Online (Sandbox Code Playgroud)

我有一些问题:

  1. 破坏的顺序是否定义明确?(即使C类和D类在不同的源文件中定义)
  2. 如果它被明确定义,这种行为是否可移植?

mol*_*ilo 8

这个结构的要点是施加一个施工顺序(因此也就是一个破坏顺序).

施工

由于这些是局部静态变量,因此构造顺序由Instance第一次调用它们各自函数的顺序决定.

由于完成了main,因此完全指定了施工顺序.

使订单未指定的唯一方法是,如果您在不同的翻译单元中使用静态初始化,例如,如果有的话

C& the_c = C::Instance();
Run Code Online (Sandbox Code Playgroud)

而另一个

D& the_d = D::Instance();
Run Code Online (Sandbox Code Playgroud)

毁坏

使用静态存储破坏对象与构造顺序相反.

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;
};
Run Code Online (Sandbox Code Playgroud)