Singleton Design Pattern in C++, not so simple!

Almost every C++ interview I go to, the candidate will claim that they know Singleton Design Pattern. In my mind, I started calling it the interview pattern 😀. But most of the time, people are not able to discuss the pattern in details. I guess, Singleton’s simplicity and short implementation makes people overlook its hidden complexities. That’s what we will discuss here.

So, what is a Singleton class? It’s a class that restricts the number of instantiations to exactly one. It makes the object behave like a unique global object.

Usage of Singleton

Singleton patterns are normally used to create a logging functionality, that will be used by all parts of a code. The logger ensures that even when multiple threads are pushing message to it at the same time they will get logged in order and won’t get garbled. The logger maintains the order with the help of a single lock for logging all messages.

Normally a singleton class encapsulates a single resource in a system. In case of the logger it can be a log file. All messages go into a single log file, so it ensures that there is only one handle to the log file.

Singleton design pattern tries to solve 2 categories of design problems:

  1. An object that represents a unique physical object or resource in the context of the program. As in case of the logger example we saw earlier.
  2. A system that is designed to work for a single object but interacts with many similar objects. It such case one can make use of Singleton for the object of interest and rest can just be regular objects of same type. With this the developers won’t confuse the regular objects with the object of interest.

Implementation

Static Singleton Pattern: An eager implementation

Based on the way Singleton’s are implemented, there can be subtle complications. We will look at various implementations and discuss them in detail. Let’s start with the simplest one.

#include <iostream>

class Singleton {
public:
    ~Singleton() { std::cout << "Singleton destroyed\n"; };
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

    static Singleton& getInstance() { return resource; }
    void use() { std::cout << "Singleton being used\n"; }
private:
    Singleton() { std::cout << "Singleton created\n"; }
    static Singleton resource;
};

Singleton Singleton::resource{};

int main() {
    std::cout << "Output:\n";
}

If you execute this code the output will look like this:

Singleton created
Output:
Singleton destroyed

Let’s discuss the implementation. We wanted to create a global unique object of Singleton. In above program, we ensured that the class can not be instantiated from outside. It’s constructor is private. Only someone with inside access can instantiate this class. Only a static method can have such access. So we made getInstance() as static and it returns the reference to internally created instance of Singleton.

Another important fact: the use of private static to create the Singleton object in the class. Due to this, the object will get created even before the program starts executing main. That is the reason why in the output we can see “Singleton created” before “Output:” i.e., the Resource object got created even before the 1st line of main got executed. Similarly, this resource will get destroyed after the last line of main.

Additionally, we have disabled copy constructor and assignment operator of Singleton. This is done to ensure one cannot create a copy of Singleton after it is returned by getInstance() method of Singleton.

In the above example we did not make use of Singleton object. Below you can see how one can get hold of the object and use it. You can replace the previous main() function with the code below.

int main() {
    std::cout << "Output:\n";
    Singleton::instance().use();
}

This will generate an output as follows:

Singleton created
Output:
Singleton being used
Singleton destroyed

This implementation is an eager implementation. It is thread safe as the object gets instantiated even before any thread can be created. It gets created before start of main. As the object is pre-instantiated there is no chance of two threads creating the object at the same time. Additionally, this is also a zero-handler implementation as the user is not creating any object of Singleton to access the resource.

Pros & cons

Pros:

  • Both implementations of static singleton are thread safe, i.e. even if multiple threads try to get hold of resource at the same time, they will always get access to only one and unique resource object. This is because the resource object is instantiated before the start of the program.
  • This implementation is thread safe.

Cons:

  • The resource object gets built even if it is not needed by program. The is what we saw in the first program where we did not make use of resource. This can slow down your program’s start up time. Also, we all love lazy initialization to eager initialization, why to do extra work that may not generate any value.
  • Additionally, when static objects are instantiated there is no way to guarantee the order of their instantiation. It is the compiler that decides the order and can differ from one compiler to another. If a Singleton object tries to access another Singleton object (DB Connector object trying to access Logger object) before its instantiation, this can lead to a crash.
  • We don’t have control over destruction sequence of Singleton objects. This can lead to a crash.

Lazy Singleton Pattern

This implementation is also called Meyer’s Singleton. It is named after its inventor Scott Meyers. The main goal of this implementation is to delay the resource creation till it is needed. Below is the code:

#include <iostream>

class Singleton {
public:
    ~Singleton() { std::cout << "Singleton destroyed\n"; };
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

    static Singleton& getInstance() { 
        static Singleton resource{};
        return resource; 
    }
    void use() { std::cout << "Singleton being used\n"; }
private:
    Singleton() { std::cout << "Singleton created\n"; }
};

int main() {
    std::cout << "Output:\n";
}

Here we removed the private class variable (the static one) and moved the creation of resource object inside getInstance() method as a local static object. The compiler guarantees that only one object of Resource will get instantiated. Unlike the static object in the previous examples this one will get created only when getInstance() method is called for the first time. The compiler also guarantees that the object creation is thread safe. So there is no need to worry if multiple threads call getInstance() at the same time. The output of above program is shown below.

Output:

Here Resource object was not instantiated as there are no calls to getInstance() method. Now lets see how to use the resource. Just change the main() function as shown below:

int main() {
    std::cout << "Output:\n";
    Singleton::instance().use();
}

This will generate following output:

Output:
Resource created
Resource being used
Resource destroyed

You can see that the resource got created after the first line in main() got executed (after printing “Output:”), i.e. when we called Singleton::instance() for the first time.

Pros & cons

Pros:

  • No upfront cost of instantiating Singleton object even when one intent to use the object. The Singleton object will only get created when needed.
  • The Lazy implementation guarantees that a Singleton object cannot refer to another Singleton object before its creation. So, no more crash at start up due to Singletons.
  • This implementation is thread safe.

Cons:

  • This technique comes with a cost. The execution time of getInstance() method in previous implementation of Singleton was faster than the lazy implementation. Why? Every time getInstance() is called, the code is internally checking whether to create an object or not. This slows down the method. By how much? If the eager ones take ~10 ns the lazy ones take ~70 ns. So, an addition of ~60 ns. For general purpose use it’s not a significant impact.
  • We don’t have control over destruction sequence of Singleton objects. This can lead to a crash.

A variant of Singleton Pattern

Now say you have a normal class and you want to convert into a singleton. What can we do?

  • We change the code of normal class such that, we hide it constructor by making it private, removes it’s copy constructor, move constructor, assignment operator and move assignment operator.
  • We can make a new Singleton class and inherit from the normal class

The first idea works, but if you are changing a class from an existing code base it will break everything. The second approach is better and it will let you use both the singleton version and the normal version of the class. Say you are working with many object of same type and you are only allowed to execute any operation on a single object but for the rest of the objects you can just observe. In such as case you can distinguish your object by wrapping it in Singleton. This way all part of your code that needs the special object can access through the new sub-class of the object.

#include <iostream>

class Resource {
public: 
    Resource() { std::cout << "Resource Created\n"; }
    ~Resource() { std::cout << "Resource Destroyed\n"; }
    void use() { std::cout << "Resource being used\n"; }
};

class SingletonRes: public Resource {
public:
    ~SingletonRes() { std::cout << "SingletonRes destroyed\n"; };
    SingletonRes(const SingletonRes&) = delete;
    SingletonRes& operator=(const SingletonRes&) = delete;

    static SingletonRes& getInstance() { 
        static SingletonRes resource{};
        return resource; 
    }
private:
    SingletonRes() { std::cout << "SingletonRes created\n"; }
};

int main() {
    std::cout << "Output:\n";

}

Now you can see that the implementation is exactly similar to our previous. The output will look like this:

Output:

Now by changing the main function a bit.

int main() {
    std::cout << "Output:\n";
    SingletonRes::getInstance().use();
}

Our new output will be:

Output:
Resource Created
SingletonRes created
Resource being used
SingletonRes destroyed
Resource Destroyed

As SingletonRes is inheriting from Resource, its instantiation called the constructor of Resource and then the constructor of SingletonRes gets executed. But you can see that, this is exactly same as the Singletons we created previously.

As mentioned earlier this implementation allows us to have both the normal Resource objects and Singleton Resource objects to co-exist side by side. Here is an example:

int main() {
    std::cout << "Output:\n";
    Resource r{};
    r.use();
    SingletonRes::getInstance().use();
}

The output looks like this:

Output:
Resource Created
Resource being used
Resource Created
SingletonRes created
Resource being used
Resource Destroyed
SingletonRes destroyed
Resource Destroyed

The 3 lines in orange are from the normal Resource object and the ones in bold green are from our special Singleton version of Resource.

Leaky Singleton Design Pattern

As we saw above, in general Singleton Design Pattern can be implemented in two ways:

  1. Static Singleton Pattern (eager instantiation of unique resource)
  2. Lazy Singleton Pattern (lazy instantiation of unique resource)

In the first method, the programmer doesn’t have any control on the order in which the Resource object will get created, especially if your code is distributed over multiple files (which is the case for all production codes). Now suppose there is another static object that depends on availability of our Resource which is yet to instantiate. This can lead to an error situation.

This problem was solved by Lazy Singleton Pattern, where we controlled the instantiation of Singleton objects. Now they gets created when needed, thus avoiding the problem mentioned above.

But we still don’t have control over the destruction sequence of Singleton objects, which happens post completion of main(). We are still in the mercy of compiler. What happens if a Singleton object gets destroyed and then some other static/Singleton object tries to access the resource? This, can lead to a crash, though the actual behavior is undefined.

In the past I may have seen this happening for an application server I worked on. We never solved the problem as the issue was always deprioritized. Why? The crash happens when we ask the server to shut down. Once the shutdown command is received the server stop accepting any new transactions and complete all in-progress transactions before shutting down. It did everything as intended and crash while trying to log something at the end. Maybe it is this problem, the logger uses a Singleton pattern and gets destroyed, post that some other static object tries to access the logger; leading to a crash.

What is the solution? The best solution would be to, not destroy any resource held by these static objects. You will say its a leak, but it’s a good leak. In this way the other static objects will still be able to use the resource. Also, the the program is moments away from its end and the OS will any way reclaim all the memory once the process ends. To prove my point, I created below code.

#include <iostream>

class Resource {
public: 
    Resource() { std::cout << "Resource Created\n"; }
    ~Resource() { std::cout << "Resource Destroyed\n"; }
    void use() { std::cout << "Resource being used\n"; }
};

class SingletonRes: public Resource {
public:
    ~SingletonRes() { std::cout << "SingletonRes destroyed\n"; };
    SingletonRes(const SingletonRes&) = delete;
    SingletonRes& operator=(const SingletonRes&) = delete;

    static SingletonRes& getInstance() { 
        static SingletonRes resource{};
        return resource; 
    }
private:
    SingletonRes() { std::cout << "SingletonRes created\n"; }
};

class Singleton {
public:
    ~Singleton() { 
        SingletonRes::getInstance().use();
        std::cout << "Singleton destroyed\n"; 
    };
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    void use() { std::cout << "Singleton being used\n"; }

    static Singleton& getInstance() { 
        static Singleton resource{};
        return resource; 
    }
private:
    Singleton() { std::cout << "Singleton created\n"; }
};

int main() {
    std::cout << ">> Program start\n";
    Singleton::getInstance().use();
    SingletonRes::getInstance().use();

    std::cout << "<< Program end:\n";
}
 

In this program I created an object of Singleton and SingletonRes. I used Lazy singleton pattern, as I wanted to control the instantiations. From the destructor of Singleton I accessed to SingletonRes. Finally, in main() I intentionally called the use() method of Singleton and SingletonRes in a sequence. This will lead to creation of Singleton first and the SingletonRes. Even though we don’t know the order in which static objects are destroyed at the end of main, I was hoping the compiler will destroy them in reverse order (that is SingletonRes gets destroyed first and then Singleton). And voilà!!

That’s exactly what happened. Remember we accessed SingletonRes from the destructor of Singleton. Ideally this should lead to a crash. We are accessing SingletonRes after it got destroyed by the compiler. Luckily or unluckily my code did not crash (may be because I am not using dynamically allocated memory) and produced an output as follows:

>> Program start
Singleton created
Singleton being used
Resource Created
SingletonRes created
Resource being used
<< Program end:
SingletonRes destroyed
Resource Destroyed
Resource being used
Singleton destroyed

So, you can see Resource getting used after it was destroyed (see the highlighted lines). Therefore, we should use a leaky Singleton. So how we can ensure this leak? We can do this by dynamically instantiating SingletonRes in its getInstance() method. The compiler will not be able to destroy the object using a pointer on its own. In above example just change the implementation of SingletonRes as shown below.

class SingletonRes: public Resource {
public:
    ~SingletonRes() { std::cout << "SingletonRes destroyed\n"; };
    SingletonRes(const SingletonRes&) = delete;
    SingletonRes& operator=(const SingletonRes&) = delete;

    static SingletonRes& getInstance() { 
        static SingletonRes* resource = new SingletonRes();
        return *resource; 
    }
private:
    SingletonRes() { std::cout << "SingletonRes created\n"; }
};

With just this change the output will look like this:

>> Program start
Singleton created
Singleton being used
Resource Created
SingletonRes created
Resource being used
Resource being used
<< Program end:
Resource being used
Singleton destroyed

Notice that the destructor of SingletonRes is not getting called anymore. This makes it safe for any other static objects to make use of our SingletonRes even when they are getting destroyed, post main().

I guess that’s all I have to say on Singleton Design Pattern. Hope I am able to take away the stigma of it being a simple pattern.