There are many places need such functional modules, such as the system log output, GUI application must be a single mouse, modem connection needs one and only need a telephone line, the operating system can only have a window manager, a PC with a keyboard.
There are many ways to implement a single case pattern, and in C + + it can even be done directly with a global variable, but the code is not elegant. Using global objects ensures easy access to instances, but it is not guaranteed to declare only one object-that is, a local instance of the same class can still be created except for a global instance.
A very good implementation is given in the book design pattern, which defines a singleton class, uses the class's private static pointer variable to point to a unique instance of the class, and obtains the instance using a public static method.
The singleton pattern manages its unique instance through the class itself, which provides a way to solve the problem. A unique instance is a normal object of a class, but when you design this class, it can only create one instance and provide global access to that instance. The unique instance class singleton hides the operation of creating an 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.
The definition is as follows:
Copy Code code as follows:
Class Csingleton
{
Other Members
Public
Static csingleton* getinstance ()
{
if (m_pinstance = NULL)//To determine whether the first call
M_pinstance = new Csingleton ();
return m_pinstance;
}
Private
Csingleton () {};
Static Csingleton * m_pinstance;
};
The only way for a user to access a unique instance is getinstance () member functions. If you do not pass this function, any attempt to create the instance will fail because the constructor of the class is private. GetInstance () is initialized with laziness, which means that its return value is created when the function is first accessed. This is a bullet-proof design-all getinstance () call returns a pointer to 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 variable multiple instance situations, such as a class that allows up to five instances.
The single example class Csingleton has the following characteristics:
It has a static pointer m_pinstance that points to a unique instance, and is private;
It has a public function that can fetch this unique instance and create it when needed;
Its constructors are private so that instances of the class cannot be created elsewhere.
Most of the time, such implementations do not have problems. An experienced reader may ask, when will the m_pinstance point of the space be released? The more serious question is, when does the destructor of this instance execute?
If there are necessary actions in the destructor of the class, such as closing the file and releasing the external resources, the above code cannot implement this requirement. We need a way to normally delete the instance.
You can call getinstance () at the end of the program and drop the delete action on the returned pointer. This can achieve functionality, but not only ugly, but also error prone. Because such additional code is easily forgotten, it is also difficult to guarantee that after the delete, no code calls the GetInstance function.
A good way to do this is to let the class know that it will delete itself at the right time, or to hang its own operation at a suitable point in the operating system so that it is automatically executed at the right time.
We know that at the end of the program, all global variables are automatically destructor. In fact, the system also destructors the static member variables of all classes, just as these static members are global variables. With this feature, we can define a static member variable in a singleton class, and its only job is to delete an instance of a singleton class in the destructor. As in the following code, the Cgarbo class (Garbo means garbage worker):
Copy Code code as follows:
Class Csingleton
{
Other Members
Public
Static csingleton* getinstance ();
Private
Csingleton () {};
Static Csingleton * m_pinstance;
Class Cgarbo//Its only job is to delete an instance of Csingleton in a destructor
{
Public
~cgarbo ()
{
if (csingleton::m_pinstance)
Delete csingleton::m_pinstance;
}
}
Static Cgabor Garbo; Defines a static member whose destructor is automatically invoked by the system at the end of the program
};
A class Cgarbo is defined as a private inline class of Csingleton in case the class is abused elsewhere.
At the end of the program, the system calls the Csingleton static member Garbo, which deletes a single instance of the singleton.
Freeing a single Instance object with this method has the following characteristics:
Defining a proprietary nested class within a single instance class;
Defines a private, static member in a single class that is specifically for release;
At the end of the program, the characteristics of global variables are reconstructed and the final release time is chosen.
Code that uses a single example does not require any action and does not care about the release of the object.
Further discussion
But adding a static object of a class is always unsatisfactory, so someone uses the following method to reproduce the implementation of the single example and solve its corresponding problem, the code is as follows:
Copy Code code as follows:
Class Csingleton
{
Other Members
Public
Static Singleton &getinstance ()
{
static Singleton instance;
return instance;
}
Private
Singleton () {};
};
Using local static variables, a very powerful way to fully implement the characteristics of a single case, and less code, there is no need to worry about a single example of the problem of destruction.
However, there are problems with this approach, and when the following methods are used, the problem arises.
Singleton Singleton = Singleton:: getinstance ();
In doing so, there is a problem with a class copy, which violates the nature of the single example. The problem arises because the compiler generates a default constructor for the class to support the 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 a single example, when the leader means that the getinstance () function returns a pointer rather than return a reference, the function of the code to read as follows:
Copy Code code as follows:
Static Singleton *getinstance ()
{
static Singleton instance;
Return &instance;
}
But I always feel bad, why not let the compiler not to do so. It was then that I remembered the constructor of the life class copy that could be displayed, and the overload = operator, and the new single instance class was as follows:
Copy Code code as follows:
Class Singleton
{
Other Members
Public
Static Singleton &getinstance ()
{
static Singleton instance;
return instance;
}
Private
Singleton () {};
Singleton (const Singleton);
Singleton & operate = (const singleton&);
};
About Singleton (const Singleton); and Singleton & operate = (const singleton&); functions, which need to be declared private, and only declared not implemented. In this way, if you use the above method to make a single case, whether in the friend class or other, the compiler is an error.
I don't know if such a single example class will still have a problem, but in the program this kind of use is basically no problem.
Optimize the Singleton class to fit the single threaded application
Singleton uses operator new to allocate storage space for unique instances. Because the new operator is thread-safe, you can use this design template in multithreaded applications, but there is a flaw: it is necessary to destroy the instance manually with delete before the application terminates. Otherwise, not only does it cause a memory overflow, but it also causes unpredictable behavior because the singleton destructor will not be invoked at all. Single-threaded applications can easily avoid this problem by replacing dynamic instances with local static instances. The following is a slightly different implementation from the above getinstance (), which is specifically for single-threaded applications:
Copy Code code as follows:
csingleton* Csingleton:: getinstance ()
{
Static Csingleton Inst;
Return &inst;
}
The local static object instance Inst is constructed the first time the getinstance () is invoked, remains active until the application terminates, the pointer m_pinstance becomes redundant, and can be removed from the class definition, unlike the dynamically assigned object, Static objects are automatically destroyed when the application terminates, so there is no need to manually destroy the instance.
Code Learning
Copy Code code as follows:
Version One
#include <iostream>
using namespace Std;
C + + Implementation of single case class
Class Singleton
{
Private
Singleton ()//Note: Construction method 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 ();//Get Var value
void SetVar (int);//Set the value of Var
Virtual ~singleton ();
};
Construct method to implement
Singleton::singleton ()
{
This->var = 20;
cout<< "Singleton Constructor" <<endl;
}
Singleton::~singleton ()
{
cout<< "Singleton destructor" <<endl;
Delete instance;
}
Initializing static members
/*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 containing number
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
}