C++实现单件的初探.docx
《C++实现单件的初探.docx》由会员分享,可在线阅读,更多相关《C++实现单件的初探.docx(17页珍藏版)》请在冰豆网上搜索。
C++实现单件的初探
------------------------------前言------------------------------
本文介绍一个比较完善的Singleton模式,用C++语言编写完成。
本文出处已不可考,我只是在我的项目里做了测试,运行良好。
安琪
2006-3-20入库
blessedness4you@
------------------------------目录------------------------------
本文的主要内容为:
1、Singleton模式的基类
2、基本的Singleton容器
3、Singleton模板
4、引入线程保护代码
5、完整的代码
6、如何使用
------------------------------Singleton模式的基类------------------------------
1、Singleton模式的基类
首先需要统一Singleton类家族的风格,我们用宏定义全权实现构造函数、析构函数和静态的GetInstance()函数。
但每一个Singleton也许有其自己的个性,在构造和析构的时候,可能会有额外的操作,我们将其延伸至以下两个纯虚函数中来,由每个Singleton类自己去完成。
classSinglePattern
{
protected:
virtualvoidInitialInstance()=0;
virtualvoidDisposeInstance()=0;
};
------------------------------基本的Singleton容器------------------------------
2、基本的Singleton容器
我们使用auto_ptr来管理指针,使之在程序结束时会正确的得到析构。
以下为基本的一个Singleton容器,其所容指针即为自己的一个实例。
classSingleton
{
friendclassauto_ptr;
protected:
staticauto_ptrm_Instance;
protected:
__fastcallSingleton(){};
virtual~Singleton(){};
public:
staticSingleton*__fastcallGetInstance()
{
if(m_Instance.get()==NULL)
{
m_Instance.reset(newSingleton());
}
returnm_Instance.get();
}
};
auto_ptrSingleton:
:
m_Instance;
------------------------------Singleton模板------------------------------
3、Singleton模板
如果我们对每一个Singleton类都向上面所写那样,我们需要做很多重复工作。
现在我们使用模板类来包装一下。
我们只需要将上面的代码,用auto_ptr管理的指针改成模板代码即可,程序代码如下:
template
classSingleton
{
friendclassauto_ptr;
protected:
staticauto_ptrm_Instance;
protected:
__fastcallSingleton(){};
virtual~Singleton(){};
public:
staticT*__fastcallGetInstance()
{
if(m_Instance.get()==NULL)
{
m_Instance.reset(newT());
}
returnm_Instance.get();
}
};
template
auto_ptrSingleton:
:
m_Instance;
实际上你可以看见,如果编写Singleton即变成了基本的Singleton。
------------------------------引入线程保护代码------------------------------
4、引入线程保护代码
上面的代码在单线程中可以很好的工作,但在多线程环境中,会产生实例被析构再构造的假Singleton类。
这里我只引入一个简单的线程保护代码做个示例:
classCResGuard
{
public:
CResGuard(){m_lGrdCnt=0;InitializeCriticalSection(&m_cs);}
~CResGuard(){DeleteCriticalSection(&m_cs);}
//IsGuardedisusedfordebugging
BOOLIsGuarded()const{return(m_lGrdCnt>0);}
public:
classCGuard{
public:
CGuard(CResGuard&rg):
m_rg(rg){m_rg.Guard();};
~CGuard(){m_rg.Unguard();}
protected:
CResGuard&m_rg;
};
private:
voidGuard(){EnterCriticalSection(&m_cs);m_lGrdCnt++;}
voidUnguard(){m_lGrdCnt--;LeaveCriticalSection(&m_cs);}
//Guard/UnguardcanonlybeaccessedbythenestedCGuardclass.
friendclassCResGuard:
:
CGuard;
private:
CRITICAL_SECTIONm_cs;
longm_lGrdCnt;//#ofEnterCriticalSectioncalls
};
------------------------------完整的代码------------------------------
5、完整的代码
以下是完整的代码,在C++Builder6,WindowsXP编译通过。
#pragmaonce
#include
#include//线程安全使用的头文件
#ifndefSingletonH
#defineSingletonH
usingnamespacestd;
//BaseSinglePatternClass
classSinglePattern
{
protected:
virtualvoidInitialInstance()=0;
virtualvoidDisposeInstance()=0;
};
//ThreadSafeClass
classCResGuard
{
public:
CResGuard(){m_lGrdCnt=0;InitializeCriticalSection(&m_cs);}
~CResGuard(){DeleteCriticalSection(&m_cs);}
//IsGuardedisusedfordebugging
BOOLIsGuarded()const{return(m_lGrdCnt>0);}
public:
classCGuard{
public:
CGuard(CResGuard&rg):
m_rg(rg){m_rg.Guard();};
~CGuard(){m_rg.Unguard();}
protected:
CResGuard&m_rg;
};
private:
voidGuard(){EnterCriticalSection(&m_cs);m_lGrdCnt++;}
voidUnguard(){m_lGrdCnt--;LeaveCriticalSection(&m_cs);}
//Guard/UnguardcanonlybeaccessedbythenestedCGuardclass.
friendclassCResGuard:
:
CGuard;
private:
CRITICAL_SECTIONm_cs;
longm_lGrdCnt;//#ofEnterCriticalSectioncalls
};
//SingletonContainer
template
classSingleton
{
friendclassauto_ptr;
protected:
staticauto_ptrm_Instance;
staticCResGuard_rs;
protected:
__fastcallSingleton(){};
virtual~Singleton(){};
public:
staticT*__fastcallGetInstance()
{
CResGuard:
:
CGuardgd(_rs);
if(m_Instance.get()==NULL)
{
m_Instance.reset(newT());
}
returnm_Instance.get();
}
};
template
CResGuardSingleton:
:
_rs;
template
auto_ptrSingleton:
:
m_Instance;
//MACROofSingletonPatterntouse
#defineDECLARE_SINGLETON(type)\
friendclassauto_ptr;\
friendclassSingleton;\
public:
\
statictype*GetInstance()\
{\
returnSingleton:
:
GetInstance();\
}\
protected:
\
__fastcalltype()\
{\
InitialInstance();\
}\
public:
\
virtual~type()\
{\
DisposeInstance();\
}
#endif
------------------------------如何使用------------------------------
6、如何使用
在你自己需要实现Singleton模式的类,使用宏定义,并实现两个纯虚函数,即可。
以下为一个使用示例:
classMySingle:
publicSinglePattern
{
DECLARE_SINGLETON(MySingle)
protected:
virtualvoidInitialInstance(){}
virtualvoidDisposeInstance(){}
public:
voidRun(){};
};
intmain(intargc,char*argv[])
{
MySingle:
:
GetInstance()->Run();
return0;
}
classA
{
public:
staticA*GetSingleton()
{
staticboolinited=false;
if(!
inited)
{
a=newA();
inited=true;
}
returna;
}
staticvoidRelease()
{
if(NULL!
=a)
{
deletea;
a=NULL;
}
}
private:
staticA*a;
A(){}
~A(){}
};
C++实现单件的初探
在《设计模式》中有一个叫做单件(Sigleton)的模式,是用来控制创建唯一对象。
书中只讲到了如何建立Singleton对象
,对于如何来销毁此对象则只字不提。
但是对象生命的管理对于C++程序员来说是多么的重要呀。
或许Singleton只
是属于创建模式的一种,大师们认为在这里不应涉及到“销毁模式”。
有人认为Sinleton是应该在程序的退出的时候销毁的。
但是退出应该是在什么时候呢。
请看如下代码:
假设是按设计模式里的方式来写一个对象Singlton对象。
classSinglton
{
private:
staticSinglton*_insatnce;
Singlton()
{
cout<<"objectis["< }
public:
~Singlton()
{
cout<<"objectis["<"< _insatnce=0;
}
staticSinglton*GetSinglton()
{
if(_insatnce)
return_insatnce;
_insatnce=newSinglton;
return_insatnce;
}
voidDosomething()
{
cout<<"objectis["< }
};
Singlton*Singlton:
:
_insatnce=NULL;
voidfoo(inti)
{
/*
程序体
*/
if(i)
Singlton:
:
GetSinglton()->Dosomething();
/*
程序体
*/
}
intmain()
{
/*
void;
程序体
*/
foo
(1)
// if(Singlton:
:
_insatnce)
// Singlton:
:
GetSinglton();不能编译
deleteSinglton:
:
GetSinglton();
}
事实上如果在Singlton某次运行根本就没有调用过foo
(1)而只是调用了foo(0),但是还必
须得在最后程序退出时调用实际上这时候调用GetSinglton()来建立对象马上就被删除了
。
这是完全没有必要也是浪费的。
想在程序执行时使用判断语句也是行不通的。
这样的实
现还是可以改进的,使用在Singlton中再增加一个静态的成员函数CheckExistInstance来判
断对象是否存在,可以提高效率。
但这样又给对象增加了接口,增加了代码维护的开销。
但是对象在程序结束时你并不清楚是不是真的不再需要此对象了。
我们再修改代码如下。
classSinglton
{
private:
staticSinglton*_insatnce;
Singlton()
{
cout<<"objectis["< }
public:
~Singlton()
{
cout<<"objectis["<"< _insatnce=0;
}
staticSinglton*GetSinglton()
{
if(_insatnce)
return_insatnce;
_insatnce=newSinglton;
return_insatnce;
}
voidDosomething()
{
cout<<"objectis["< }
};
Singlton*Singlton:
:
_insatnce=NULL;
voidfoo(inti)
{
/*
程序体
*/
if(i)
Singlton:
:
GetSinglton()->Dosomething();
/*
程序体
*/
}
classTestSingleton
{
public:
TestSingleton()
{
Singlton:
:
GetSinglton()->Dosomething();
}
~TestSingleton()
{
Singlton:
:
GetSinglton()->Dosomething();//此处出现内存泄露
}
};
TestSingleton_test;
intmain()
{
/*
void;
程序体
*/
foo
(1);
deleteSinglton:
:
GetSinglton();
}
且看~TestSingleton()申请出来的对象应该由谁来释放呢。
由此引发了有人主张使用
引用记数器由模仿COM的Release来实现.实现代码如下
classSingleton
{
private:
staticintm_Ref;
staticSingleton*_instance;
public:
voidDoSomething()
{
cout<<"objectis["< }
staticSingleton*GetSinglton()
{
if(_instance)
{
++m_Ref;
return_instance;
}
_instance=newSingleton;
++m_Ref;
return_instance;
}
ULONGRelease()
{
--m_Ref;
if(0==m_Ref)
{
delete_instance;
_instance=NULL;
return0;
}
returnm_Ref;
}
private:
Singleton()
{
cout<<"objectis["< }
~Singleton()
{
cout<<"objectis["<"< }
};
Singleton*Singleton:
:
_instance=NULL;
intSingleton:
:
m_Ref=0;
voidfoo()
{
Singleton*p=Singleton:
:
GetSinglton();
p->DoSomething();
p->Release();
}
int_tmain(intargc,TCHAR*argv[],TCHAR*envp[])
{
Singleton*p=Singleton:
:
GetSinglton();
p->DoSomething();
p->Release();
foo();
return0;
}
这样的方式是不存在内存泄露的,并且这段代码表面上是个单件;实际上,
Singleton对象是被多次建立和销毁的,如果这个对象不像以上代码写得那么简单,
是如果在单件中申请了不小的内存,那么以上的代码是多么的不可想象呀!
更有如
果单件里记录了像使用次数那样的状态变量,那情况就更糟糕了。
事实上单件的实现并不比想像中的那样难。
我们且看
classSinglton
{
private:
Singlton()
{
cout<<"objectis["< }
public:
~Singlton()
{
cout<<"objectis["<"< }
staticSinglton&GetSinglton()
{
staticSingltons;
returns;
}
voidDosomething()
{
cout<<"objectis["<