Introduction to the singleton mode in C ++

Source: Internet
Author: User

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 a global object to easily access the instance, but you cannot declare only one object. That is to say, you can still create local instances of the same class except for one global instance.

The design pattern book provides a very good implementation that defines a singleton class and uses the Private Static pointer variable of the class to point to the unique instance of the class, obtain the instance using a public static method.

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:

Copy codeThe Code is as follows: class CSingleton
{
// Other members
Public:
Static CSingleton * GetInstance ()
{
If (m_pInstance = NULL) // determines whether the first call is successful.
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. GetInstance () uses lazy initialization, that is, 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 situations where multiple instances can be changed. For example, a class allows a maximum of five instances.

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.

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.

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.
A proper method is to let the class know how to delete itself, or to put the delete operation on a proper point in the operating system, make it automatically executed when appropriate.
We know that at the end of the program, the system will automatically 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 ):

Copy codeThe Code is as follows: 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 in the destructor.
{
Public:
~ CGarbo ()
{
If (CSingleton: m_pInstance)
Delete CSingleton: m_pInstance;
}
}
Static CGabor Garbo; // defines a Static member. When the program ends, the system automatically calls 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:
Define a proprietary nested class within the singleton class;
Define Private Static members dedicated for release in the singleton class;
The program analyzes the global variables at the end and selects the final release time;
The Singleton Code does not require any operation and does not need to care about the release of objects.

Further discussion

However, it is always unsatisfactory to add a static object of a class, so some people use the following method to reproduce the problem of implementing singleton and solving it. The Code is as follows:

Copy codeThe 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 = 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:

Copy codeThe Code is as follows: static Singleton * GetInstance ()
{
Static Singleton instance;
Return & instance;
}

But I always think it's not good. Why don't 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:

Copy codeThe Code 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 Singleton class 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 is a defect: You must manually use delete to destroy the instance before the application ends. 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:

Copy codeThe Code is as follows: 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.

Code Learning

Copy codeThe Code is as follows: // version 1
# Include <iostream>
Using namespace std;
// C ++ implementation of the Singleton class
Class Singleton
{
Private:
Singleton (); // note: the constructor method is private.

Static Singleton * instance; // unique instance
Int var; // member variable (for testing)
Public:
Static Singleton * GetInstance (); // factory method (used to obtain an instance)
Int getVar (); // obtain the value of var
Void setVar (int); // sets the value of var.
Virtual ~ Singleton ();
};
// Constructor implementation
Singleton: Singleton ()
{
This-> var = 20;
Cout <"Singleton Constructor" <endl;
}
Singleton ::~ Singleton ()
{
Cout <"Singleton Destructor" <endl;
// Delete instance;
}
// Initialize static members
/* 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 content
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
}

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.