Go: Singleton mode in C + +

Source: Internet
Author: User

A singleton pattern in C + +

The singleton mode, also known as the single-piece mode, the list mode, is probably the most widely used design pattern. The intent is to ensure that a class has only one instance and provides a global access point to access it, which is shared by all program modules. There are many places need such a function module, such as the log output of the system, the GUI application must be a single mouse, the modem connection requires one and only need a phone line, the operating system can only have a window manager, a PC with a keyboard.
There are many ways to implement a singleton pattern, and in C + + you can even do this directly with a global variable, but the code is not elegant. Using global objects guarantees easy access to the instance, but there is no guarantee that only one object is declared-that is, in addition to a global instance, a local instance of the same class can still be created.
In design mode, a very good implementation is given, defining a singleton class, using the class's private static pointer variable to point to the unique instance of the class, and fetching the instance with a public static method.
The singleton pattern manages its only instance through the class itself, which provides a way to solve the problem. The only instance is a generic object of the class, but when you design the class, it allows it to create only one instance and provide global access to the instance. The unique instance class singleton hides the operation that created the instance in a static member function. It is customary to call this member function instance (), whose return value is a pointer to a unique instance.

Defined as follows:

[CPP]View Plaincopy
  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 if first call
  12. M_pinstance = new Csingleton ();
  13. return m_pinstance;
  14. }
  15. };
  16. Csingleton * csingleton::m_pinstance = NULL; Static member variables initialize the implementation of similar function bodies without regard to access rights.

The only way a user accesses a unique instance is the getinstance () member function. If this function is not passed, any attempt to create an instance will fail because the class's constructor is private. GetInstance () uses lazy initialization, which means that its return value is created when the function is first accessed. This is a bulletproof design-all calls after getinstance () return a pointer to the same instance:

csingleton* P1 = Csingleton:: getinstance ();
csingleton* P2 = p1->getinstance ();
Csingleton & ref = * Csingleton:: getinstance ();
With a slight modification to the getinstance, this design template can be applied to variable multi-instance situations, such as a class that allows up to five instances.

The Csingleton of a singleton class has the following characteristics:
It has a static pointer to a unique instance, m_pinstance, and is private;
It has a public function that can fetch this unique instance and create it when needed;
Its constructor is private so that an instance of the class cannot be created elsewhere.
Most of the time, there is no problem with this implementation. An experienced reader may ask, when does the space M_pinstance point to be released? The more serious question is, when does the destructor for the instance execute?
If there is a necessary action in the destructor of the class, such as closing the file and releasing the external resource, the code above cannot implement this requirement. We need a way to delete the instance as normal.
You can call getinstance () at the end of the program and drop the delete operation on the returned pointer. This can be done with functionality, but not only ugly, but also error-prone. Because such additional code is easily forgotten, it is also difficult to guarantee that no code can call the GetInstance function after the delete.
A good way to do this is to let the class know to delete itself at the right time, or to suspend its operation on an appropriate point in the operating system so that it is automatically executed at the appropriate time.
We know that at the end of the program, all global variables are automatically refactored. In fact, the system will also deconstruct the static member variables of all classes, just as these static members are also global variables. With this feature, we can define one such static member variable in a singleton class, and its only job is to delete instances of the Singleton class in the destructor. The Cgarbo class in the following code (garbo means garbage worker):

[CPP]View Plaincopy
  1. Class Csingleton
  2. {
  3. Private
  4. Csingleton ()
  5. {
  6. }
  7. static Csingleton *m_pinstance;
  8. class Cgarbo //Its only job is to delete an instance of Csingleton in a 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, and the system will automatically call its destructor when the program ends
  18. Public
  19. Static Csingleton * getinstance ()
  20. {
  21. if (m_pinstance = = NULL) //Determine if first call
  22. M_pinstance = new Csingleton ();
  23. return m_pinstance;
  24. }
  25. };

The class Cgarbo is defined as a private inline class of Csingleton, in case the class is abused elsewhere.
At the end of the program run, the system calls the destructor of the static member Garbo of Csingleton, which deletes the unique instance of the singleton.
Using this method to release a singleton object has the following characteristics:
Define a proprietary nested class within a singleton class;
Defining a private static member specifically for release within a singleton class;
Using the program at the end of the analysis of the characteristics of global variables, select the final release time;
Using a singleton code does not require any action, and you do not have to care about the object's release.

A further discussion

But adding a static object to a class is always a bit less satisfying, so someone can use the following method to re-implement the singleton and solve its corresponding problem, the code is as follows:

[CPP]View Plaincopy
  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 variable
  11. return instance;
  12. }
  13. };

The use of local static variables, a very powerful method, fully realize the characteristics of the single case, and the code is less, and do not worry about the single-instance destruction problem.
However, there are problems with using this method, and when you use a singleton as follows,
Singleton Singleton = Singleton:: getinstance ();
In doing so, there is a problem with a copy of the class, which violates the characteristics of the singleton. The problem arises because the compiler generates a default constructor for the class to support a copy of the class.

Finally there is no way, we want to prohibit the class copy and class assignment, prohibit the programmer in this way to use the singleton, then the leader means that the getinstance () function returns a pointer instead of returning a reference, the code of the function is changed to the following:

[CPP]View Plaincopy
  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 variable
  11. return &instance;
  12. }
  13. };

But I always feel bad, why not let the compiler do not do it. That's when I think of the constructor that can be displayed for the declaration class copy, and the overloaded = operator, the new Singleton class is as follows:

[CPP]View Plaincopy
  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 variable
  13. return instance;
  14. }
  15. };

About Singleton (const Singleton), and Singleton & operate = (const singleton&); functions, which need to be declared as private, and only declarations are not implemented. This way, if you use the above method to make a singleton, whether in the friend class or otherwise, the compiler is an error.
I do not know if such a singleton class will still have problems, but in the program this kind of use has basically no problem.

For thread safety and exception security, the following extensions can be made

[CPP]View Plaincopy
  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. Class Singleton
  16. {
  17. Private
  18. Singleton ();
  19. Singleton (const Singleton &);
  20. singleton& operator = (const Singleton &);
  21. Public
  22. static Singleton *instantialize ();
  23. static Singleton *pinstance;
  24. Static CCriticalSection CS;
  25. };
  26. singleton* Singleton::p instance = 0;
  27. singleton* singleton::instantialize ()
  28. {
  29. if (pinstance = = NULL)
  30. { //double check
  31. Lock Lock (CS); //Use lock for thread safety and resource management classes for exception security
  32. //Using the Resource management class, when an exception is thrown, the resource management class object is destroyed, and the destructor always occurs whether the exception is thrown or the statement block ends.
  33. if (pinstance = = NULL)
  34. {
  35. Pinstance = new Singleton ();
  36. }
  37. }
  38. return pinstance;
  39. }


The reason why the Instantialize function inside the pinstance is not NULL to make two judgments, because the method called once the object is generated, pinstance = = NULL In most cases is false, if the original method, each time the acquisition of the instance need to lock, Efficiency is too low. The improved method only needs to be locked at the first call, which can greatly improve the efficiency.

Go: Singleton mode in C + +

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.