One question per day (27) -- C ++ Singleton Mode

Source: Internet
Author: User
1. Introduction:

The Singleton mode is also called the singleton mode and the singleton mode. It may be the most widely used design mode. The intention is to ensure that a class has only one instance and provides a global access point for it. This instance is shared by all program modules. There are many areas where such functional modules are needed, such as system log output. GUI applications must be single-mouse, modem connections need one and only one telephone line, and the operating system can only have one window manager, a pc is connected to a keyboard.

Singleton mode has many implementation methods. In C ++, you can even use a global variable to do this, but such code is not elegant. You can use global objects to access instances conveniently, but you cannot declare only one object. That is to say, you can still createLocal instance.

1.1. Constructor

The design pattern book provides a very good implementation and definesSingleton type, UsePrivate Static pointer variablePoint to a unique instance of the class and usePublic static methodObtain the instance.

The Singleton mode manages its unique instances through the class itself. This feature provides a solution to the problem. A unique instance is a common object of A Class. When designing this class, you can only create one instance and provide global access to this instance. Singleton, a unique instance type, hides the operation for creating an instance in the static member function. Traditionally, this member function is called instance (). Its return value is the pointer of a unique instance.

Definition:

Class csingleton {// other members public: static csingleton * getinstance () {If (m_pinstance = NULL) // determine whether to call m_pinstance = new csingleton (); Return m_pinstance ;} PRIVATE: csingleton () {}; static csingleton * m_pinstance ;};

Only the getinstance () member function is used to access a unique instance. If you do not use this function, any attempt to create an instance will fail because the class constructor is private. Use getinstance ()Lazy InitializationThat is to say, its return value is created when this function is accessed for the first time. This is a bulletproof Design -- all calls after getinstance () return pointers of the same instance:

  • Csingleton * P1 = csingleton: getinstance ();
  • Csingleton * P2 = p1-> getinstance ();
  • Csingleton & ref = * csingleton: getinstance ();

With a slight modification to getinstance, this design template can be applied to the case of variable multiple instances. For example, a class allows a maximum of three instances (the following 2. Questions ).

 

The Singleton class csingleton has the following features:

It has a static pointer m_pinstance pointing to a unique instance and is private;

It has a public function that obtains the unique instance and creates the instance as needed;

Its constructor is private, so that you cannot create instances of this class elsewhere.

 

1. 2. Structure Analysis

Most of the time, this implementation will not be faulty. Experienced readers may ask when the space pointed to by m_pinstance will be released? The more serious problem is, when will the destructor of the instance be executed?

If there are necessary operations in the class destructor, such as closing the file and releasing external resources, the above Code cannot meet this requirement. We need a method to delete the instance normally.

1. You can call getinstance () at the end of the program and delete the returned pointer. This can implement functions, but it is not only ugly, but also prone to errors. Because such additional code is easy to forget, and it is difficult to ensure that after the delete operation, no code can call the getinstance function.

2. A proper methodIt is to let this class know to delete itself at the right time, or to put the delete operation on a suitable point in the operating system, so that it can be automatically executed at the right time.

We know that when the program ends, the system willAutomatically analyze all global variables. In fact, the system will analyze the static member variables of all classes, just like these static members are also global variables. With this feature, we can define such a static member variable in the singleton class, and its only job is to delete the singleton class instance in the destructor. The cgarbo class in the following code (Garbo stands for spam workers ):

Class csingleton {// other members public: static csingleton * getinstance (); Private: csingleton () {}; static csingleton * m_pinstance; class cgarbo // Its only job is to delete the csingleton instance {public: ~ In the destructor :~ Cgarbo () {If (csingleton: m_pinstance) delete csingleton: m_pinstance ;}} static cgabor Garbo; // defines a static member. When the program ends, the system will automatically call its destructor };

Class cgarbo is defined as the private embedded class of csingleton to prevent this class from being abused elsewhere.

When the program runs, the system calls the Garbo destructor, a static member of csingleton. This destructor deletes the unique instance of a single instance.

 

Releasing a singleton object in this way has the following features:

1. Define a proprietary nested class within the singleton class;

2. Define Private Static members dedicated for release in the singleton class;

3. analyze the global variables at the end of the program and select the final release time;

4. The Singleton Code does not require any operations, and you do not have to worry about the release of objects.

1. 3. Further Discussion

However, it is always unsatisfactory to add a static object of a class, so some people use the following method to implement singleton and solve its corresponding problems. The Code is as follows:

Class csingleton {// other members public: static Singleton & getinstance () {static Singleton instance; return instance;} PRIVATE: Singleton (){};};

 

 

The use of local static variables is a very powerful method to fully implement the single-instance features, and the amount of code is less, there is no need to worry about the single-instance Destruction problem.

However, this method may also cause problems. When the following method is used as a Singleton,

Singleton = singleton: getinstance ();

In this case, a copy class problem occurs, which violates the features of the singleton instance. This problem occurs because the compiler generates a default constructor for the class to support copying the class.

Finally, there is no way. We need to disable copying classes and assigning values to classes, and prohibit programmers from using Singleton instances in this way. At that time, the leading means that the getinstance () function returns a pointer instead of a reference, the function code is changed to the following:

static Singleton *GetInstance(){static  Singleton instance;return  &instance;}

 

But I don't know how to let the compiler do this. This reminds me of the constructor that can be copied to the life class and the overload = Operator. The new Singleton class is as follows:

Class Singleton {// other members public: static Singleton & getinstance () {static Singleton instance; return instance;} PRIVATE: Singleton () {}; Singleton (const Singleton ); singleton & operate = (const Singleton &);};

For Singleton (const Singleton); and Singleton & operate = (const Singleton &); functions, they must be declared private and declared as not implemented. In this way, if the preceding method is used to use a Singleton, the compiler reports an error, whether in the youyuan class or other methods.

I don't know if such a singleton class still has problems, but there is almost no problem in using it in the program.

 

. Optimized the singleton class to make it suitable for single-threaded applications

Singleton uses the new operator to allocate storage space for a unique instance. Because the new operator is thread-safe, you can use this design template in multi-threaded applications, but there isDefects: The instance must be manually destroyed with Delete before the application is terminated. Otherwise, not only memory overflow, but also unpredictable behavior, because the singleton destructor will not be called at all. By replacing dynamic instances with local static instances, a single-threaded application can easily avoid this problem. The following is a slightly different implementation from the above getinstance (), which is specially used for single-threaded applications:

CSingleton* CSingleton :: GetInstance(){static CSingleton inst;return &inst;}

The local static object instance inst is constructed when getinstance () is called for the first time and remains active until the application is terminated. The pointer m_pinstance becomes redundant and can be deleted from the class definition, unlike dynamic objects, static objects are automatically destroyed when the application ends, so you do not have to manually destroy the instance.

 

2. Code:
// Version 1 # include <iostream> using namespace STD; // class Singleton {PRIVATE: Singleton () for the c ++ implementation of the Singleton class; // note: constructor Private Static Singleton * instance; // unique instance int var; // member variable (used for testing) Public: static Singleton * getinstance (); // The Factory method (used to obtain the instance) int getvar (); // obtain the VaR value void setvar (INT); // set the VaR value virtual ~ Singleton () ;}; // constructor implementation singleton: Singleton () {This-> Var = 20; cout <"Singleton constructor" <Endl;} singleton :: ~ Singleton () {cout <"Singleton destructor" <Endl; // Delete instance;} // initialize a static member/* Singleton * singleton: instance = NULL; singleton * singleton: getinstance () {If (null = instance) instance = new Singleton (); Return instance;} */Singleton * singleton: instance = new Singleton; singleton * singleton: getinstance () {return instance;} // seter & getter count int singleton: getvar () {return this-> var;} void singleton :: setvar (INT var) {This-> Var = var;} // main void main () {Singleton * ton1 = singleton: getinstance (); Singleton * ton2 = singleton :: getinstance (); If (ton1 = ton2) cout <"ton1 = ton2" <Endl; cout <"ton1 Var =" <ton1-> getvar () <Endl; cout <"ton2 Var =" <ton2-> getvar () <Endl; ton1-> setvar (150 ); cout <"ton1 Var =" <ton1-> getvar () <Endl; cout <"ton2 Var =" <ton2-> getvar () <Endl; delete singleton: getinstance (); // must be explicitly deleted}

 

 

3. Question:

Implement a class, which cannot be inherited and can only be instantiated three times (Note the location of the number of judgments, the constructor must be private)

# Include <iostream> using namespace STD; Class A {public: static A * intial () {If (n <3) return new A; else return 0;} void print () {cout <n <Endl;} PRIVATE: A () {n ++;} static int n ;}; int A: n = 0; int main () {A * P = NULL; // do not instantiate for (INT I = 0; I <5; I ++) {// run a static function to judge n <3, then call the constructor n ++ and call print. Therefore, the output is 1, 2, 3 P = A: intial (); If (P! = NULL) {P-> Print ();}}}

 

Reference:

Http://blog.csdn.net/boyhailong/article/details/6645681

Http://blog.csdn.net/clamreason/article/details/8105960

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.