introduce
Writing code in C + + has been a few years, from the beginning of the process of programming, to a simple object-oriented programming, and then to the application of various design patterns, and then the model programming, and now have to go back to the process of hurrying feet, so all the way, every step into a new stage has the wind is very comfortable feeling, Instead of abandoning the previous stage of programming, you have a deeper understanding of what kind of programming approach is in use. Recently want to do a summary of C + + template application, and then have been thinking about what to write, on their own this brain capacity and poor ink, what can be written ... Then honestly write the project to use it. First, in the application of the single case, then there is the Observer mode, then ... Again.
Background single case mode, single from its role, looks like the GOF proposed design pattern of the simplest one, Baidu Encyclopedia explained: Through a single example mode can ensure that a class only one instance of the system and this example is easy to access outside, so as to facilitate the control of the number of instances and save system resources. In this way, it's easy to think of a simple method, as shown in the following code:
Class resource
{
protected:
static resource inst_;
//! Constructor
resource () {} public
:
static resource& instance () {return
inst_;
}
Others ...
};
Static implement
This is used directly in the customer Code: resource::instance (). Call_func (); This code looks simple and easy to use, single case mode, and so on. As the code more write more, need "single example" class also more and more, it doesn't matter, write a new single case class , suit, a copy of the code above, so the mechanical code began, and soon the code appeared a lot of this kind of people look a bit uncomfortable things. One day the demand changed, one of the classes to derive a subclass, so scrambling to remove the static function in the class, remove the static variable, the constructor into public, and then write subclasses, and then in the manner of the example copy "single Case Characteristics" ... The ground was shattered.
Finally can't stand, change ... In a different way, this time can not be so no moral, at least these "single example" features can be reused, first of all to determine how these "characteristics" from the specific class.
Implement
Inheritance, can not solve the single instance of the object access interface problem, combination, aggregation, Bishi, could think of only the template this path. Write this template class first:
Template<class t>
class Singleton
{
private:
static T inst_;
Singleton () {}
public:static t& instance () {return
inst_;
}
};
Static implement in some place
Well, the interface has been removed from the specific class, and then how to "bind" the specific class to achieve the problem of a single example. Here template parameter T is a specific class, the most intuitive is two ways: Inheritance Way class Resource:public singleton<resource>; Direct use of the way singleton<resource>. After inheriting, the resource class cannot be inherited, otherwise there is a static instance function in the subclass, and the base class object is returned, which ... Sibuxiang Then the second one, seemingly no problem.
Wait a minute, Singleton. This template class provides a single instance with a static concrete class, that this particular example object must be defined somewhere before use (usually in CPP file), otherwise the compiler will not agree, well, put it in the specific class of CPP file, you know, Whether it is a global object or a (global) static object, the main function is initialized after the program starts, and if the resource class occupies a large virtual memory space and does not require initialization of the program, it is no doubt a waste, so lazy Initialization is a must.
It's okay to set the static variable in the singleton class to a pointer, and then in instance it becomes this:
Static t& instance () {
if (!inst_)
inst_ = new T;
return *inst_;
}
In this way, the concrete class object is constructed only when the instance function is invoked, the static Destroy function is written, and the function is called before the program exits to deconstruct the concrete class object:
Static t& Destroy () {
if (inst_) {
delete inst_;
Inst_ = NULL;
}
}
The question is, where should I call the Destroy function? If it can be like a global variable, it would be nice to call the destructor automatically when the program exits.
Google, find the atexit function, use it to register a program to exit the callback function, just, the destroy function registered to this bar. As a result, when the program exits, the individual instances of the specific class are automatically deleted, as is the case after the experiment. There is also a small problem, using the Atexit function to register a callback function with a limit of 32, also means that this method can only be used to generate up to 32 single object, I go ... It seems that you can only redesign a class to manage all the single object pointers, called Singleton_mgr, which provides two static interfaces:
Append is used to add the newly generated single instance object pointer to the management container, and to invoke the Append registration instance object within the instance function;
Clear is used to register the callback when the program exits, and then to delete the single Instance object in this function iteration;
It looks like this:
static void Append (void* obj_ptr);
static void Clear ();
Here's another potential problem: The Apend argument must be void*, because each single instance class is independent and cannot add a common base class to these specific classes, so it can only be converted into void* to container management, but When the clear function is invoked, it does not know how to release the corresponding memory of these void*, because the calling destructor needs to know the specific type, so in addition to the single Instance object pointer, the APPEND function call requires an additional function pointer parameter to release each concrete class object. This function can just use SINGLETON<T>::d Estroy function, and attach a void* parameter to this function, Singleton<t>::d The Estroy function now looks like this:
static void Destroy (void* obj_ptr)
{
if (m_p && obj_ptr = = m_p) {
delete m_p;
m_p = 0;
}
}
Well, this basically completes the abstract of a single example. Attached code singleton_mgr:
#include <map> #include <boost/function.hpp> #include <boost/thread.hpp> class Singleton_mgr {Typede
F boost::function<void (void*) > destructor;
typedef std::map<void*, destructor> Dstr_map;
typedef Boost::mutex Mutex;
Private:static Dstr_map Mp_;
static Mutex mtx_;
Singleton_mgr () {} ~singleton_mgr () {} public:static void append (void* obj_ptr, const destructor& DSTR);
static void Clear ();
};
Singleton_mgr.cpp:singleton_mgr::d str_map singleton_mgr::mp_;
void Singleton_mgr::append (void* obj_ptr, const destructor& dstr) {if (!obj_ptr) return;
Boost::unique_lock<mutex> Guard (MTX_);
if (Mp_.empty ()) std::atexit (clear);
MP_[OBJ_PTR] = dstr; } void Singleton_mgr::clear () {for (Dstr_map::iterator it = Mp_.begin (); it!= mp_.end (); ++it) {It->second (it->
;
} mp_.clear (); }//Singleton template class: Template<typename t> class Singleton {Private:singleton () {} public:static t& ()
{
// First, determine whether the (atomic operation) if (!m_p) {//is already initialized to ensure thread safety, lock boost::unique_lock<mutex> Guard (MTX_);
/* * * * * * * * * It is very likely that the first moment of locking the mutex, M_p has been assigned to another thread succeeded, * * so you need to again determine whether the m_p value is empty.
*/if (!m_p) m_p = Makeinstance ();
return *m_p;
} private:static t* makeinstance () {assert (!m_p);
t* p = new T ();
Singleton_mgr::append ((void*) p, &destroy);
return p;
} static void Destroy (Void* obj_ptr) {boost::unique_lock<mutex> Guard (mtx_);
if (m_p && obj_ptr = = m_p) {delete m_p;
m_p = 0;
} static t* m_p;
};
Template<typename t> t* singleton<t>::m_p = static_cast<t*> (0);
Template<typename t> Boost::mutext singleton<t>::mtx_;
Use like this://class Test_case//{//public://void Func () {}//};
typedef singleton<test_case> Single_test_case; Single_test_case::instance (). Func ();