C++实现单件的初探.docx

上传人:b****0 文档编号:12479326 上传时间:2023-04-19 格式:DOCX 页数:17 大小:19.27KB
下载 相关 举报
C++实现单件的初探.docx_第1页
第1页 / 共17页
C++实现单件的初探.docx_第2页
第2页 / 共17页
C++实现单件的初探.docx_第3页
第3页 / 共17页
C++实现单件的初探.docx_第4页
第4页 / 共17页
C++实现单件的初探.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

C++实现单件的初探.docx

《C++实现单件的初探.docx》由会员分享,可在线阅读,更多相关《C++实现单件的初探.docx(17页珍藏版)》请在冰豆网上搜索。

C++实现单件的初探.docx

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["<

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 简洁抽象

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1