Article source: blog.csdn.net/hackbuteer1…

The singleton pattern, also known as singleton or monad pattern, is probably the most widely used design pattern. The intent is to ensure that a class has only one instance and to provide a global access point to it that is shared by all program modules. There are many places where such functional modules are needed, such as logging output of the system, GUI applications must be single mouse, MODEM connection requires one and only one telephone line, operating system can only have one window manager, one PC with one keyboard. There are many ways to implement the singleton pattern, and in C++ it is even possible to do this directly with a global variable, but such code is very inelegant. Using global objects guarantees easy access to instances, but it does not guarantee that only one object can be declared — that is, local instances of the same class can still be created with the exception of one global object. A good implementation, described in Design Patterns, defines a singleton class that uses a private static pointer variable to point to a unique instance of the class and uses a public static method to retrieve that instance. The singleton pattern provides a solution to the problem by managing its unique instance through the class itself. The only instance is a normal object of the class, but the class is designed so that it can create only one instance and provide global access to that instance. The Singleton class hides the creation of the instance in static member functions. This member function is conventionally called Instance(), and its return value is a pointer to a unique Instance. \

The definition is as follows:

[cpp]  view plain copy

  1. class CSingleton  
  2. {  
  3. private:  
  4. CSingleton() // Constructor is private
  5.     {  
  6.     }  
  7.     static CSingleton *m_pInstance;  
  8. public:  
  9.     static CSingleton * GetInstance()  
  10.     {  
  11. If (m_pInstance == NULL) // Determine whether it is the first call
  12.             m_pInstance = new CSingleton();  
  13.         return m_pInstance;  
  14.     }  
  15. };  

The only way for a user to access a unique instance is the GetInstance() member function. Without this function, any attempt to create an instance will fail because the constructor of the class is private. GetInstance() uses lazy initialization, which means that its return value is created when the function is first accessed. This is bulletproof — all calls to GetInstance() return a pointer to the same instance: CSingleton* p1 = CSingleton :: GetInstance(); CSingleton* p2 = p1->GetInstance(); CSingleton & ref = * CSingleton :: GetInstance(); With a few modifications to GetInstance, this design template can be used for variable-multi-instance situations, such as a maximum of five instances per class. The singleton class CSingleton has the following characteristics: it has a static pointer m_pInstance to a unique instance and is private; It has a public function that takes this unique instance and creates it if needed; Its constructor is private, so instances of the class cannot be created from elsewhere. Most of the time, this implementation will be fine. Experienced readers may ask, when is the space to which m_pInstance points freed? The more serious question is, when does the destructor for this instance execute? If there are necessary actions in the class’s destructor behavior, such as closing a file or freeing external resources, then the above code does not fulfill this requirement. We need a way to delete the instance normally. You can call GetInstance() at the end of the program and drop delete on the returned pointer. It’s functional, but it’s ugly and error-prone. Such additional code is easy to forget, and it is hard to guarantee that no code will call the GetInstance function after delete. A good way to do this is to let the class know when to delete itself, or to hang the deletion at an appropriate point in the operating system so that it can be automatically executed at the appropriate time. We know that at the end of the program, the system automatically destructs all global variables. In fact, the system also destructs all static member variables of the class as if they were global variables. Using this feature, we can define such a static member variable in a singleton class whose only job is to remove instances of the singleton class in the destructor. The CGarbo class (Garbo for garbage worker) in the following code: \

[cpp]  view plain copy

  1. class CSingleton  
  2. {  
  3. private:  
  4.     CSingleton()  
  5.     {  
  6.     }  
  7.     static CSingleton *m_pInstance;  
  8. Class CGarbo // Its only job is to remove the instance of CSingleton in the destructor
  9.     {  
  10.     public:  
  11.         ~CGarbo()  
  12.         {  
  13.             if(CSingleton::m_pInstance)  
  14.                 delete CSingleton::m_pInstance;  
  15.         }  
  16.     };  
  17. static CGarbo Garbo; // Define a static member variable whose destructor is automatically called when the program ends
  18. public:  
  19.     static CSingleton * GetInstance()  
  20.     {  
  21. If (m_pInstance == NULL) // Determine whether it is the first call
  22.             m_pInstance = new CSingleton();  
  23.         return m_pInstance;  
  24.     }  
  25. };  

The CGarbo class is defined as a private embedded class of CSingleton to prevent it from being abused elsewhere. At the end of the program, the system calls the destructor of CSingleton’s static member Garbo, which removes the unique instance of the singleton. Freeing a singleton in this way has the following characteristics: defining a proprietary nested class within the singleton class; Define private static members within a singleton class that are used exclusively for release. The final release time is selected by using the property of global variables destructed at the end of the program. Code that uses singletons requires no action and does not care about object release. Further discussion \

However, adding a static object of a class is always unsatisfactory, so someone used the following method to re-implement the singleton and solve its corresponding problems, the code is as follows:

[cpp]  view plain copy

  1. class CSingleton  
  2. {  
  3. private:  
  4. CSingleton() // Constructor is private
  5.     {  
  6.     }  
  7. public:  
  8.     static CSingleton & GetInstance()  
  9.     {  
  10. static CSingleton instance; // Local static variables
  11.         return instance;  
  12.     }  
  13. };  

Using local static variables, a very powerful method, fully implements singletons with less code and no need to worry about singletons destruction. Singleton = Singleton :: GetInstance(); Singleton = Singleton :: GetInstance(); Doing so creates a class copy problem, which violates the singleton nature. The reason for this problem is that the compiler generates a default constructor for the class to support copying the class. \

The GetInstance() function returns a pointer instead of a reference. The code for this function reads:

[cpp]  view plain copy

  1. class CSingleton  
  2. {  
  3. private:  
  4. CSingleton() // Constructor is private
  5.     {  
  6.     }  
  7. public:  
  8.     static CSingleton * GetInstance()  
  9.     {  
  10. static CSingleton instance; // Local static variables
  11.         return &instance;  
  12.     }  
  13. };  

But I always feel bad, why not tell the compiler not to do that. Then I remembered that I could display the constructor that declared a copy of the class, and the overload = operator. The new singleton class looks like this:

[cpp]  view plain copy

  1. class CSingleton  
  2. {  
  3. private:  
  4. CSingleton() // Constructor is private
  5.     {  
  6.     }  
  7.     CSingleton(const CSingleton &);  
  8.     CSingleton & operator = (const CSingleton &);  
  9. public:  
  10.     static CSingleton & GetInstance()  
  11.     {  
  12. static CSingleton instance; // Local static variables
  13.         return instance;  
  14.     }  
  15. };  

About the Singleton (const Singleton); And Singleton& Singleton = (const Singleton&); Function, which needs to be declared private and only declared but not implemented. This way, if you use a singleton in the same way as above, whether in a friend class or otherwise, the compiler will report an error. I don’t know if this singleton class is still a problem, but it’s pretty much fine to use it this way in programs. For thread safety, exception safety, you can do the following extension \

[cpp]  view plain copy

  1. class Lock  
  2. {  
  3. private:         
  4.     CCriticalSection m_cs;  
  5. public:  
  6.     Lock(CCriticalSection  cs) : m_cs(cs)  
  7.     {  
  8.         m_cs.Lock();  
  9.     }  
  10.     ~Lock()  
  11.     {  
  12.         m_cs.Unlock();  
  13.     }  
  14. };  
  15.   
  16. class Singleton  
  17. {  
  18. private:  
  19.     Singleton();  
  20.     Singleton(const Singleton &);  
  21.     Singleton& operator = (const Singleton &);  
  22.   
  23. public:  
  24.     static Singleton *Instantialize();  
  25.     static Singleton *pInstance;  
  26.     static CCriticalSection cs;  
  27. };  
  28.   
  29. Singleton* Singleton::pInstance = 0;  
  30.   
  31. Singleton* Singleton::Instantialize()  
  32. {  
  33.     if(pInstance == NULL)  
  34.     {   //double check  
  35. Lock lock(cs); // Implement thread safety with lock, implement exception safety with resource management class
  36. // With resource management classes, when an exception is thrown, the resource management object is destructed, which always happens either because the exception is thrown or because the block ends.
  37.         if(pInstance == NULL)  
  38.         {  
  39.             pInstance = new Singleton();  
  40.         }  
  41.     }  
  42.     return pInstance;  
  43. }  

Instantialize () : pInstance == NULL; Instantialize () : pInstance == NULL; Instantialize () : pInstance == NULL; However, the improved method only needs to lock at the first call, which can greatly improve efficiency. \