Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Singleton: how can destructor be called twice?

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

But I cannot understand why in the next example if I instantiate Singleton in variable inst its destructor 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();
}

Output:

construction!
foo!
destruction!
destruction!

Live demo

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

Or it was not destroyed? Why?

like image 674
vladon Avatar asked Jun 02 '15 18:06

vladon


People also ask

Why is destructor getting called twice?

C++ destructors are called twice for local objects when exiting a function via a nested return statement.

Can we create 2 objects for Singleton class?

The Singleton's purpose is to control object creation, limiting the number to one but allowing the flexibility to create more objects if the situation changes. Since there is only one Singleton instance, any instance fields of a Singleton will occur only once per class, just like static fields.

Does Singleton need destructor?

Because all the member functions of this class are static and the class has no instance variables, it is not required that the class be instantiated. The member functions can be used without an instance of the class. Thus there is no need to implement constructors or a destructor for this class.

How do you destroy a Singleton?

There is no way to destroy a Singleton without breaking the Singleton property. As others have said, maybe a Singleton isn't appropriate here. If the number of instances of the class can go down to zero, then it's not a Singleton.


2 Answers

This line

Singleton inst = Singleton::getInstance();

Should be

Singleton& inst = Singleton::getInstance();

Then you would only see one destructor call.

The way it is written, Singleton::getInstance() returns a reference, but then copies it to inst. So both the Singleton returned from your function and the copy are destroyed. You never saw the copy get constructed because the default constructor was not used, the copy constructor was.

In the second method, the reference is returned, then you just have inst be a reference to that Singleton instead of making a copy.

As other's have mentioned, you can make the class non-copyable and non-movable 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
like image 150
Cory Kramer Avatar answered Oct 21 '22 01:10

Cory Kramer


The line

Singleton inst = Singleton::getInstance();

copies your instance with the auto-generated copy-constructor. To prevent this from happening, add

Singleton( const Singleton& ) = delete;

to your class to prevent those accidential copies. To make sure that even more obscure mistakes are caught, also add

void operator=( const Singleton& ) = delete;

as well. You don't have to explicitly delete move construction or assignment as the compiler will not generate them with the other (deleted) members declared.

like image 30
Daniel Frey Avatar answered Oct 21 '22 02:10

Daniel Frey