在高手的代码里面看到单例模式,觉得挺有意思,先整理学习下,然后利用自己的知识联想下,:)。
单例模式,是在工程里面,此类只能实例化一个对象,并且这个对象呢,全局共享的(只要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; Singleon::Cleaner Singleon::clr; 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类的外面还得初始化下clr:
Singleon::Cleaner Singleon::clr;
现在这个单例类Singleon OK了,可以随便使用。保险起见,我们再看看内存检测的结果:
valgrind ./main ==15732== Memcheck, a memory error detector ==15732== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. ==15732== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info ==15732== Command: ./mainj ==15732== singleon str:test singleon str:test1 ==15732== ==15732== HEAP SUMMARY: ==15732== in use at exit: 0 bytes in 0 blocks ==15732== total heap usage: 1 allocs, 1 frees, 1 bytes allocated ==15732== ==15732== All heap blocks were freed -- no leaks are possible ==15732== ==15732== For counts of detected and suppressed errors, rerun with: -v ==15732== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
其中:==15732== total heap usage: 1 allocs, 1 frees, 1 bytes allocated
==15732==
==15732== All heap blocks were freed -- no leaks are possible
如果一个类是单例类,直接使用上面的定义,没问题。如果有多个类呢,每个类都需要这样定义么,那代码的重复就多了。
是不是可以抽象下,把公共的东西定义到一个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);
参考:
单例模板类(静态单例模版类),还有另外一种设计,很精妙:
template <typename T> class ssingleton { protected: struct object_creator { object_creator() { ssingleton<T>::instance(); } inline void do_nothing() const { } }; static object_creator create_object; ssingleton(){}; public: typedef T object_type; static object_type & instance() { static object_type obj; create_object.do_nothing(); return obj; } static object_type& getInstance() { return instance(); } }; template <typename T> typename ssingleton<T>::object_creator ssingleton<T>::create_object;
联想以后继续。。。
douban.com/note/356749278/
douban.com/note/356749293/
douban.com/note/356749305/
douban.com/note/356749318/
douban.com/note/356749326/
douban.com/note/356749334/
douban.com/note/356749341/
douban.com/note/356749354/
douban.com/note/356749363/
douban.com/note/356749384/
douban.com/note/356749468/
douban.com/note/356749484/
douban.com/note/356749503/
douban.com/note/356749523/
douban.com/note/356749556/
douban.com/note/356749593/
douban.com/note/356749611/
douban.com/note/356749646/
douban.com/note/356749666/
douban.com/note/356749695/
douban.com/note/356749817/
douban.com/note/356749830/
douban.com/note/356749853/
douban.com/note/356749867/
douban.com/note/356749883/
douban.com/note/356749927/
douban.com/note/356749967/
douban.com/note/356749984/
douban.com/note/356750045/
douban.com/note/356750069/
douban.com/note/356750191/
douban.com/note/356750216/
douban.com/note/356750230/
douban.com/note/356750262/
douban.com/note/356750287/
douban.com/note/356750304/
douban.com/note/356750311/
douban.com/note/356750324/
douban.com/note/356750344/
douban.com/note/356750386/
douban.com/note/356750438/
douban.com/note/356750453/
douban.com/note/356750485/
douban.com/note/356750504/
douban.com/note/356750536/
douban.com/note/356750557/
douban.com/note/356750561/
douban.com/note/356750584/
douban.com/note/356750596/
douban.com/note/356750606/
douban.com/note/356750682/
douban.com/note/356750713/
douban.com/note/356750731/
douban.com/note/356750769/
douban.com/note/356750770/
douban.com/note/356750784/
douban.com/note/356750828/
douban.com/note/356750839/
douban.com/note/356750848/
douban.com/note/356750859/
douban.com/note/356750933/
douban.com/note/356750952/
douban.com/note/356750980/
douban.com/note/356751001/
douban.com/note/356751031/
douban.com/note/356751052/
douban.com/note/356751064/
douban.com/note/356751072/
douban.com/note/356751087/
douban.com/note/356751100/
douban.com/note/356751172/
douban.com/note/356751203/
douban.com/note/356751225/
douban.com/note/356751240/
douban.com/note/356751263/
douban.com/note/356751284/
douban.com/note/356751295/
douban.com/note/356751303/
douban.com/note/356751315/
douban.com/note/356751325/
douban.com/note/356751359/
douban.com/note/356751373/
douban.com/note/356751383/
douban.com/note/356751392/
douban.com/note/356751402/
douban.com/note/356751416/
douban.com/note/356751428/
douban.com/note/356751451/
douban.com/note/356751476/
douban.com/note/356751511/
douban.com/note/356751564/
douban.com/note/356751572/
douban.com/note/356751588/
douban.com/note/356751594/
douban.com/note/356751615/
douban.com/note/356751649/
douban.com/note/356751689/
douban.com/note/356751725/
douban.com/note/356751747/
douban.com/note/356751778/
douban.com/note/356751843/
douban.com/note/356751850/
douban.com/note/356751861/
douban.com/note/356751871/
douban.com/note/356751889/
douban.com/note/356751896/
douban.com/note/356751909/
douban.com/note/356751943/
douban.com/note/356751964/
douban.com/note/356751999/