Singleton: How can a destructor be called twice?

I asked a question about singleton implementation a few minutes ago, I have a very good answer from @LightnessRacesinOrbit.

But I can’t understand why in the following example, if I create a Singleton instance in the inst variable, its destructor is called twice?

 #include <iostream> class Singleton { public: ~Singleton() { std::cout << "destruction!\n"; } static Singleton& getInstance() { static Singleton instance; return instance; } void foo() { std::cout << "foo!\n"; } private: Singleton() { std::cout << "construction!\n"; } }; int main() { Singleton inst = Singleton::getInstance(); inst.foo(); } 

Conclusion:

 construction! foo! destruction! destruction! 

Live demo

To be more correct, I understand why it is called twice. But I can’t understand how it can be called twice if, after the first destructor, the class instance was destroyed? Why is there no exception?

Or was it not destroyed? Why?

+5
source share
4 answers

This line

 Singleton inst = Singleton::getInstance(); 

Must be

 Singleton& inst = Singleton::getInstance(); 

Then you will see only one call to the destructor.

The write method, Singleton::getInstance() returns the link, and then copies to inst . Thus, as Singleton returned from your function , so , the copy is destroyed. You never saw a copy to be built because the default constructor was not used, the copy constructor was.

The second method returns a link, then you just inst should be a link to Singleton instead of creating a copy.

As already mentioned, you can make the class not copied and immovable to prevent this

 Singleton(Singleton const&) = delete; // Copy construct Singleton(Singleton&&) = delete; // Move construct Singleton& operator=(Singleton const&) = delete; // Copy assign Singleton& operator=(Singleton &&) = delete; // Move assign 
+16
source

Line

 Singleton inst = Singleton::getInstance(); 

copies your instance using the auto-generator-constructor. To prevent this, add

 Singleton( const Singleton& ) = delete; 

for your class to prevent these copies. To make sure that even more obscure errors are caught, add

 void operator=( const Singleton& ) = delete; 

. You do not need to explicitly remove the move construct or assignment, since the compiler will not generate them with the declared other (deleted) members.

+8
source

Try adding an open copy constructor:

 Singleton(const Singleton&) { std::cout << "copy construction!\n"; } 

Your result will be as follows:

 construction! copy construction! foo! destruction! destruction! 

There are two “solitary” living ones because one of getInstance() copied. To avoid unintentional copying of singlets, you must remove the copy constructor and assignment operators:

 Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; 
+3
source

You can hide a singleton in a regular class without showing its static nature:

 #include <iostream> #include <string> class Singleton // A bad name for a specific class, you should not generalize { private: struct Context { std::string name; Context() : name("Hello") {} }; private: static Context& context() { static Context result; return result; } public: const std::string& name() const { return context().name; } }; int main() { Singleton a; std::cout << a.name() << '\n'; } 
+2
source

All Articles