Meyers Singleton Destruction Order

To the following code:

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 

I have a couple of questions:

  • Is the destruction order defined correctly? (even if classes C and D are defined in different source files)
  • If this is correctly defined, is this portable behavior?
+6
source share
2 answers

The point of this construction is the superposition of the construction order (and, therefore, the order of destruction).

Construction

Since these are local static variables, the construction order is determined by the order in which their respective Instance functions are called for the first time.

Since this is done in main , the construction order is fully specified.

The only way to make an order unspecified is to use it in static initialization in different translation units, for example, if you have

 C& the_c = C::Instance(); 

and the other has

 D& the_d = D::Instance(); 

Destruction

Destroying objects with static storage is the reverse of the build order.

3.6.3, Termination, paragraph 1:

If the completion of the constructor or dynamic initialization of an object with a static storage duration is sequenced to another, the completion of the destructor of the second is sequenced before the start of the destructor of the first.

Thus, the order of destruction is completely determined by the order of construction.

Note that this syntax construct is well indicated, even if one of them depends on the other, regardless of the unit of translation.

That is, it is completely safe, and it does not matter where it is defined:

 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; }; 
+8
source

In general, the order of destruction of static objects, including static local variables (which are used in your case), is undefined.

To ensure the order of destruction, one template that I used is to use on std :: shared_ptr. For example, if you want singleton C to remain valid until singleton D is destroyed, you can save shared_ptr <C> to 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_; }; 
-one
source

Source: https://habr.com/ru/post/1011687/


All Articles