Singleton is most used Design pattern in the software industry and also most asked Design Pattern in interview so need to know.
C++ Singleton Design Pattern :
Definition:
It Ensures a class has ONE instance and provide a global access to it.
Class Diagram:
In layman language:
Class will create ONLY one instance and if we get request for another object then same object will be returned. We need to provide global access (it should be accessed from outside world).
Example:
- Logger (we need to print the logs of all thread so that we need one object to do this job)
- Configuration class (we need to set the configuration concurrency, it will be used by multiple threads so we need one object)
When will we use Singleton Design pattern:
In many scenario we have a requirement that class must create a single object.
Why will we use Singleton Design pattern:
Because singleton gives the guarantee that single object will be created by class and it will be accessed globally.
Methods to implement:
- call once
- static object
- old method (double check thread safe method)
call once: This is new feature in C++11, without mutex we can create the one object with thread safe.
SingletonLogger *SingletonLogger::GetInstance() { static std::once_flag oc; static SingletonLogger* m_pinstance; std::call_once(oc, []{ static SingletonLogger obj; m_pinstance = &obj; std::cout<<"Object Address:"<<&m_pinstance<<std::endl; }); return m_pinstance; }
static object: We all know that static object is stored in data segment memory and persist in function calls and it will be live till the end of program so we can create a static object.
SingletonLogger *SingletonLogger::GetInstance() { static SingletonLogger m_pinstance; return &m_pinstance; }
old method (double check thread safe method): we will use two check condition with one mutex lock.
SingletonLogger *SingletonLogger::GetInstance() { if (m_pinstance == nullptr) { std::lock_guard<std::mutex> lock(m_mutex); if (m_pinstance == nullptr) { m_pinstance = new SingletonLogger(); } } return m_pinstance; }
source code with c++11:
/* * File:singletonLogger.cpp * This file is described the Singleton Design Pattern with help of example * Singleton Design pattern:Ensure ONLY one object will be created. * Singleton Design pattern:Provide Globall access to it. * Author: Alpha Master * Date: 18 April 2021 */ ///////////////////////////////////Header files//////////////////////////////////// #include <iostream> #include <mutex> #include <thread> //////////////////////////////////Singleton Start////////////////////////////////////// class SingletonLogger { private: std::mutex m_mutex; //Singleton's constructor should be private to prevent creation of direct object. SingletonLogger(){} ~SingletonLogger() {} SingletonLogger(const SingletonLogger &other) = delete; // Disallow copying void operator=(const SingletonLogger &) = delete; // Disallow copying public: static SingletonLogger *GetInstance(); void Print(const std::string str); }; SingletonLogger *SingletonLogger::GetInstance() { static std::once_flag oc; static SingletonLogger* m_pinstance; std::call_once(oc, []{ static SingletonLogger obj; m_pinstance = &obj; std::cout<<"Object Address:"<<&m_pinstance<<std::endl; }); return m_pinstance; } //Print Function of Logger, this is basic function to explain the use of singleton Pattern // we can add according to our requirement. void SingletonLogger::Print(const std::string str) { std::lock_guard<std::mutex> lock(m_mutex); std::cout<<" value:"<<str<<std::endl; } ///////////////////////////////////////////////Singleton END//////////////////////////////// void ThreadOne(){ // Thread One std::this_thread::sleep_for(std::chrono::milliseconds(1000)); SingletonLogger::GetInstance()->Print("Thread ONE is executing"); } void ThreadTwo(){ // Thread Two std::this_thread::sleep_for(std::chrono::milliseconds(1000)); SingletonLogger::GetInstance()->Print("Thread TWO is executing"); } int main() { std::thread t1(ThreadOne); std::thread t2(ThreadTwo); //waiting SingletonLogger::GetInstance()->Print("Parent process is Waiting for threads"); t1.join(); t2.join(); SingletonLogger::GetInstance()->Print("Check that address should be printed only once"); SingletonLogger::GetInstance()->Print("Parent process saying BYE BYE"); return 0; }
Output:
Object Address:0x604328 value:Parent process is Waiting for threads value:Thread TWO is executing value:Thread ONE is executing value:Check that address should be printed only once value:Parent process saying BYE BYE