C++ Singleton
Introduction
C++ singleton is a specially designed class of which there can only be at most one instance in the entire program. It’s commonly used the global object implementations, such as memory pool.
In this blog post, I would like to discuss the C++ singleton class implementations.
C++ Singleton
C++ Singleton Implementation Features
Because singleton class can only be constructed once and it cannot be copied and it is globally accessible, we will have the following features for the implementation.
- The copy constructor and copy assignment are deleted.
- The constructor is private and the class has to be constructed via a public static method.
- The class methods, including the singleton object instantiation, have to be thread-safe.
C++ Singleton Application Example
The following application will consume the singleton class implementation from the header file.
1 |
|
In the following sections, I will show a couple of singleton class implementations in a header file.
C++ 11 Implementation
The following singleton class C++ 11 implementation is thread-safe for the singleton instance instantiation and the set_value
method. The get_value
was designed to be thread-unsafe on purpose. But it can be implemented to be thread-safe with appropriate locks.
1 |
|
1 | $ g++ singleton.hpp main.cpp -o main -std=c++11 |
There are many problems with this design and implementation. It uses a global mutex which is exposed to the user, which is not a good design in my opinion. There is a lock used in the get_instance
function so that the instantiation of the singleton instance is thread-safe. However, this also means after the singleton is instantiated whenever we call get_instance
there is a lock which is sometimes not desirable. For example, if we want to get the value in a thread-unsafe fashion by Singleton::get_instance()->get_value()
, the lock is unnecessary. We could make a copy of the singleton instance pointer Singleton::get_instance()
and use the pointer to access the get_value
function to bypass the lock. But this does not seem to be a good practice either.
C++ 17 Implementation
The following singleton class C++ 17 implementation is based on the C++ 11 implementation. They are almost the same except that the static singleton pointer now can be initialized inside the class. Therefore, the C++ 17 implementation has exactly the same drawbacks as the C++ 11 implementation.
1 |
|
1 | $ g++ singleton.hpp main.cpp -o main -std=c++17 |
Scott Meyers Implementation
As we mentioned previously, the lock used in the get_instance
for ensuring the thread-safe singleton instance instantiation is very annoying since it’s only useful for protecting the singleton instance instantiation but not anymore later on. Since C++ 11, the storage_duration guarantees that, “If multiple threads attempt to initialize the same static local variable concurrently, the initialization occurs exactly once (similar behavior can be obtained for arbitrary functions with std::call_once
)”.
This feature can be used for ensuring the singleton instance is initialized exactly once in a multithreading environment without using a lock. Before C++ 11, there is no such guarantee and the static local variable can be initialized multiple times if multiple threads are trying to access it for the first time simultaneously. The implementation that takes the advantage of such a feature was created by Scott Meyers and it was usually referred as Meyers singleton.
1 |
|
1 | $ g++ singleton.hpp main.cpp -o main -std=c++11 |
Notice that because the singleton instance is a static local variable that is allocated at the beginning of the program instead of a pointer, I said singleton instance initialization instead of singleton instance instantiation. The mutex can now be a member variable of the class instead of a global variable.
Therefore, the Meyers singleton implementation looks much clever and cleaner than the other singleton implementations.
C++ Singleton VS Static Class
C++ singleton class shares lots similarities with a class whose member variables and functions are all static. I don’t know what to call for the latter class. Let’s call it “static class” for now. To some extent, the “static class” can have most of the key features that the singleton class has, including that it can only be constructed once and it cannot be copied and it is globally accessible.
The major differences I think are:
- The singleton instance can be lazy instantiated whereas the static class is created at the beginning of the program.
- The static variables in the static class cannot use other static variables or functions for initialization, because the order of the static variable initialization is not defined.
Final Remarks
The C++ singleton class is global so thread-safety has always to be considered in the implementation.
References
C++ Singleton