在高手的代码里面看到单例模式,觉得挺有意思,先整理学习下,然后利用自己的知识联想下,:)。
单例模式,是在工程里面,此类只能实例化一个对象,并且这个对象呢,全局共享的(只要include此类的头文件就可以了)。
先看看单例模式的实现吧:
#include<stdio.h> #include<iostream> using namespace std; class Singleon { public: static string param; static Singleon& getinstance() { if(s == NULL) { s = new Singleon(); } return *s; } void Print(const char* str) { cout << "singleon str:" << str <<endl; } private: Singleon(){}; static Singleon *s; }; Singleon* Singleon::s = NULL; int main() { Singleon::getinstance().Print("test"); Singleon::getinstance().Print("test1"); return 0; }
在上面代码中,我们可以看到,两次调用Singleon类的方法Print,只生成一个对象,按照一般的类的实现,就会生成两个对象,再调用其方法(当然这个例子,可以就一个对象,调用两次方法,如果是多个.cpp文件,就可以看出它的威力了)。我们来编译此这段代码,可以把代码保持为文件名:main.cpp,编译如下:
g++ main.cpp -o main valgrind ./main ==5627== Memcheck, a memory error detector ==5627== Copyright (C) 2002-2012, and GNU GPL‘d, by Julian Seward et al. ==5627== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info ==5627== Command: ./mainj ==5627== singleon str:test singleon str:test1 ==5627== ==5627== HEAP SUMMARY: ==5627== in use at exit: 1 bytes in 1 blocks ==5627== total heap usage: 1 allocs, 0 frees, 1 bytes allocated ==5627== ==5627== LEAK SUMMARY: ==5627== definitely lost: 0 bytes in 0 blocks ==5627== indirectly lost: 0 bytes in 0 blocks ==5627== possibly lost: 0 bytes in 0 blocks ==5627== still reachable: 1 bytes in 1 blocks ==5627== suppressed: 0 bytes in 0 blocks ==5627== Rerun with --leak-check=full to see details of leaked memory ==5627== ==5627== For counts of detected and suppressed errors, rerun with: -v ==5627== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
细心地我们,很容易看出有一处内存分配了(如下),程序执行完,还没有释放,怎么办呢?
==5627== total heap usage: 1 allocs, 0 frees, 1 bytes allocated
程序中使用new实例化对象,需要使用delete释放对象,自始至终我们都没有使用delete,所以。。。
一种方法是实例化对象后,直接使用delete。这个方法有个问题是什么时候使用delete呢,每次使用都delete,那代价太大了,并且对于多线程程序,还容易出错。
下面就介绍另外一种方法,在单例会类中定义一个类,用于清空new的实例化对象。
#include<stdio.h> #include<iostream> using namespace std; class Singleon { public: static string param; static Singleon& getinstance() { if(s == NULL) { s = new Singleon(); } return *s; } void Print(const char* str) { cout << "singleon str:" << str <<endl; } private: class Cleaner { ~Cleaner() { if(s != NULL) delete s; } }; static Cleaner clr; Singleon(){}; static Singleon *s; }; Singleon* Singleon::s = NULL; int main() { Singleon::getinstance().Print("test"); Singleon::getinstance().Print("test1"); return 0; }单例类Singleon中定义Cleaner类(如下),并实例化其静态对象,在程序结束的时候可以自动调用析构函数,进而调用delete。
class Cleaner
{
~Cleaner()
{
if(s != NULL)
delete s;
}
};static Cleaner clr;
现在这个单例类Singleon OK了,可以随便使用。
如果一个类是单例类,直接使用上面的定义,没问题。如果有多个类呢,每个类都需要这样定义么,那代码的重复就多了。
是不是可以抽象下,把公共的东西定义到一个base类里面,每个单例类都继承它。单例类里面有个很重要的特性是初始化对象,base类只能初始化自己的对象,没法初始化子类的对象,还是有些问题。
这个时候就需要使用泛类的思想了。来看看代码:
template <typename T> class singleton { static Lock l; static T *t; public: static string param; static T& instance() { if (t == NULL) { l.lock(); if (t == NULL) { t = new T(); } l.unlock(); } return *t; } static T& getInstance() { return instance(); } }; template <typename T> T *singleton<T>::t=NULL; template <typename T> Lock singleton<T>::l; template <typename T> string singleton<T>::param=""; class Synonym:public singleton<Synonym> { }; class Adcode:public singleton<Adcode> { }; class District:public singleton<District> { };咱们定义了三个单例化类了,Synonym,Adcode, District。代码不多,挺简洁的。
最后来看看这三个类的实例化:
Synonym::instance(); Adcode::instance(); District::instance(); //调用方法 Synonym::instance().Print(str); Adcode::instance().Print(str); District::instance().Print(str); //当然也可以使用自己的方法 Synonym::instance().A(str); Adcode::instance().B(str); District::instance().C(str);
联想以后继续。。。