Concepts:
The Singleton design pattern is a creational design pattern that ensures that only one instance of a class is created and provides a global point of access to that instance.
The basic idea behind the Singleton pattern is to create a class that has:
- a private constructor so that it cannot be instantiated from outside the class.
- a static method that returns the same instance of the class every time it is called.
- This instance is created the first time the static method is called, and subsequent calls to the static method simply return the existing instance.
There are 2 basic ways of implementing a singleton.
Concerns when implementing Singleton could be whether the implementation is "thread-safe". Thus, mutex could be used to provide additional protection.
Implementation
Implement Singleton with "Static"
- When
static
keyword is used, variable or data members or functions cannot be modified again. Thus declaringstatic
function to initialize an object of the class prevent reinitializing the constructor of that class again. - This program illustrate a singleton class:
- a contructor is in protected/private mode. Thus it cannot be accessed outside of the class. The constructor can only be called via a
static instance()
function. - the static function
instance()
can only be called once.
- a contructor is in protected/private mode. Thus it cannot be accessed outside of the class. The constructor can only be called via a
class Singleton
{
public:
static Singleton& Instance()
{
static Singleton inst;
return inst;
}
protected:
Singleton(); // Prevent construction
Singleton(const Singleton&); // Prevent construction by copying
Singleton& operator=(const Singleton&); // Prevent assignment
~Singleton(); // Prevent unwanted destruction
};
Note: Scott Meyers mentions in his Effective Modern C++ book, that deleted functions should generally be public as it results in better error messages due to the compilers behavior to check accessibility before deleted status Note : delete function is a feature in C++11, as explained here: https://stackoverflow.com/questions/5513881/meaning-of-delete-after-function-declaration. It disallows copying , disallow doing anything else when the function is called that way. Reference: https://stackoverflow.com/questions/13047526/difference-between-singleton-implemention-using-pointer-and-using-static-object
Implementation using Pointers:
class Singleton
{
private:
static Singleton *p_inst;
Singleton();
public:
Singleton(Singleton const&) = delete;
void operator=(Singleton const&) = delete;
static Singleton * instance()
{
if (!p_inst)
{
p_inst = new Singleton();
}
return p_inst;
}
};
Better thread-safe implementation
Thread-safe implementation with C++ is done with mutex. The following program illustrates its usage:#include "iostream"
#include "mutex"
#include "thread"
class Singleton {
private:
static Singleton * instance;
static std::mutex mtx;
static int Count; // a count variable to indicate that all call of singleton modify the same values
Singleton(){};
Singleton( const Singleton & ) = delete;
public:
static Singleton * getInstance(){
std::lock_guard<std::mutex> lock(mtx);
if (!instance)
{
instance = new Singleton();
std::cout<<"create singleton"<<std::endl;
Count++; // Count must be static to be included in a static function
std::cout<<" count: "<<Count<<std::endl;
}
else {
std::cout<<"singleton already run"<<std::endl;
}
}
};
// static member requires initialization outside of the class, using scope resolution
Singleton* Singleton::instance = nullptr ;
std::mutex Singleton::mtx;
int Singleton::Count = 0;
int main(){
std::thread t1([]() {
Singleton * s1 = Singleton::getInstance();
Singleton * s2 = Singleton::getInstance();
});
std::thread t2([]() {
Singleton * s3 = Singleton::getInstance();
Singleton * s4 = Singleton::getInstance();
});
t1.join();
t2.join();
return 0;
}