小窥模板元编程

Singleton 的C++实现

皮贝贝 posted @ 2008年8月23日 18:07 in 模式之灾 with tags 单件 单件模式 c++ , 2058 阅读

 

一、GoF描述: 
      “保证一个class 只有一个实体(instance),并为它提供一个全局访问点(global
access point)”。

        可以看出Singleton的几个特性:@一个Singleton对象负责自身的诞生和摧毁,外部对象
无法另外构造和摧毁一个Singleton对象,因为这些属于Singleton对象的内部工作了。@一个
Singleton对象提供了一个统一的外部接口,外部只能通过此来获取并使用该Singleton对
象。

二、现实世界里的Singleton 
       Singleton是存在最广泛的一种模式。
       可以是资源配置,可以是数据库连接。差不多都是出于效率和管理集中方便两方面考虑。
   
三、框架实现 
        先根据描述来给出一个框架,有一个Instance()接口来向外界提供对象。再次,让外界无
法自己构建和析构,所以设构造函数、析构函数等不为用户所用的为私有。  

  1.         template <class Type>
  2.         class Singleton
  3.         {
  4.         public:
  5.                 static Type* Instance();
  6.  
  7.         private:
  8.                 Singleton(){}
  9.                 ~Singleton(){}
  10.                 Singleton& operator = ( const Singleton& ){}
  11.         };
  12.  

        当然要设计成为单件的类也要遵循自我构建性,即不允许用户构建摧毁,所以应设这些函数
为私有。要使其正常工作,必须让我们的|Singleton|模板可以构建摧毁。这就要设为友元了,
在类内部必须有这样一句( 假使类名为A ): 

  1.         friend class Singleton <A>;

       这样类A的声明如下:

  1.         class A
  2.         {
  3.         public:
  4.                 // 提供给用户使用的一些方法
  5.         private:
  6.                 A();
  7.                 ~A();
  8.                 A& operator = ( const A& );
  9.         };
  10.  
  11.         typedef Singleton <A> SA;

       这样,我们在使用A的时候,像下面一样: 

  1.         SA::Instance()->方法();

四、具化Singleton 
      你可以用 static 静态类来实现内部对象管理,但是static有诸多不妙之处,所以我
用了指针管理,指针来管理对象的构建销毁,自然就用 std提供的 auto_ptr 了。
  为了实现多线程的对象安全性构建,封装了下面一个锁类,利用windows的关键区机制:

  1. ////////////////////////////////////////////////////////////////////////////////
  2. //      类名:     SingleThreadModal
  3. //      功能:     单线程模型
  4. //      实现:     空内容以兼容线程接口
  5. ////////////////////////////////////////////////////////////////////////////////
  6. class SingleThreadModal
  7. {
  8. public:
  9.         class Lock
  10.         {
  11.         public:
  12.                 Lock(){}
  13.                 Lock( SingleThreadModal& ) {}
  14.         };
  15. };
  16.  
  17. ////////////////////////////////////////////////////////////////////////////////
  18. //      类名:     MultiThreadModal
  19. //      功能:     多线程模型
  20. //            处理数据安全,
  21. //      实现:     以windows关键区加锁与解锁实现
  22. ////////////////////////////////////////////////////////////////////////////////
  23. class MultiThreadModal
  24. {
  25. public:
  26.         MultiThreadModal();
  27.         ~MultiThreadModal();
  28.  
  29.         class Lock
  30.         {
  31.                 MultiThreadModal& m_Host;
  32.         public:
  33.                 //Lock() {}
  34.                 Lock( MultiThreadModal& Host )
  35.                         : m_Host( Host )
  36.                 {
  37.                         m_Host.Guard();
  38.                 }
  39.                 ~Lock()
  40.                 {
  41.                         m_Host.UnGuard();
  42.                 }
  43.         };
  44.  
  45. protected:
  46.         void Guard();
  47.         void UnGuard();
  48. private:
  49.         CRITICAL_SECTION m_cs;
  50. };

        使用一个内嵌类,主要是为了防止用户的结对编程的考虑不足,就像new和delete一
样,很多时候我们忘记了delete,这里用内嵌类也是出于此考虑,把解锁工作由C++
的语言机制来自动处理,这里用的是C++的生命期控制。
        另外,提供一个空壳的 SingleThreadModal 是为了接口统一。

  所以我们的 Singleton 可以实现了:

  1.         //------------------------------------------------------------------------------
  2.         //      宏名:     DECLARE_SINGLETON_CLASS                单线程单件模型声明
  3.         //            DECLARE_SINGLETON_CLASS_MT        多线程单件模型声明
  4.         //------------------------------------------------------------------------------
  5.         #define DECLARE_SINGLETON_CLASS( Type )  \
  6.                 friend class std::auto_ptr <Type>;            \
  7.                 friend class Singleton <Type, SingleThreadModal>;
  8.  
  9.         #define DECLARE_SINGLETON_CLASS_MT( Type )       \
  10.                 friend class std::auto_ptr <Type>;      \
  11.                 friend class Singleton <Type, MultiThreadModal>;
  12.  
  13.         ////////////////////////////////////////////////////////////////////////////////
  14.         //      类名:     Singleton
  15.         //      功能:     单件
  16.         //      参数:     Type------型别
  17.         //            ThreadModal-----单线程或多线程选择,
  18.         ////////////////////////////////////////////////////////////////////////////////
  19.  
  20.         template <class Type,
  21.                  class ThreadModal = SingleThreadModal>
  22.         class Singleton
  23.         {
  24.         public:
  25.                 static inline Type* Instance();
  26.  
  27.         private:
  28.                 static ThreadModal                  m_Thread;               // 线程
  29.                 static std::auto_ptr <Type>          m_pObj;
  30.         };
  31.  
  32.         //------------------------------------------------------------------------------
  33.         //      Singleton 数据成员
  34.         //------------------------------------------------------------------------------
  35.         template <class Type, class ThreadModal>
  36.         ThreadModal                    Singleton <Type, ThreadModal> ::m_Thread;
  37.  
  38.         template <class Type, class ThreadModal>
  39.         typename std::auto_ptr <Type>  
  40.                                                 Singleton <Type, ThreadModal> ::m_pObj;
  41.  
  42.  
  43.         //------------------------------------------------------------------------------
  44.         //      Singleton 成员函数
  45.         //------------------------------------------------------------------------------
  46.         template <class Type, class ThreadModal>
  47.         inline Type* Singleton <Type, ThreadModal> ::Instance()
  48.         {
  49.                 if ( 0 == m_pObj.get() )
  50.                 {
  51.                         typename ThreadModal::Lock      Guard( m_Thread );
  52.                         if ( 0 == m_pObj.get() )
  53.                         {
  54.                                 m_pObj.reset( new Type() );
  55.                         }
  56.                 }
  57.                 return m_pObj.get();
  58.         }
  59.  

       值得一提的是,在 Instance() 的实现体重,采用了双检测模式,主要是为了加锁与
解锁只是在第一次尚未构建的情况下发生,构建完成后,其此时所有在检测中中断的线程都
完成后,以后所有的线程要想获得对象就不必再用锁管理了。
      当然假如了线程管理,框架比前所述的框架多了点东西(这点微不足道的东西让我们更
心里踏实).

五、设计改进 
         当然这只是一个可以正常工作,并且在大多数情况下,这已经足够了。要想设计一个完整的
符合所有情况的,还要从 生命期管理的角度添加策略了。
 


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter