关闭

三种单例模式的C++实现

标签: C++单例模式饿汉式懒汉式
13187人阅读 评论(4) 收藏 举报

简介

        因为在设计或开发中,肯定会有这么一种情况,一个类只能有一个对象被创建,如果有多个对象的话,可能会导致状态的混乱和不一致。这种情况下,单例模式是最恰当的解决办法。它有很多种实现方式,各自的特性不相同,使用的情形也不相同。今天要实现的是常用的三种,分别是饿汉式、懒汉式和多线程式。

        通过单例模式, 可以做到:

1. 确保一个类只有一个实例被建立 
2. 提供了一个对对象的全局访问指针 
3. 在不影响单例类的客户端的情况下允许将来有多个实例


懒汉式

      懒汉式的特点是延迟加载,比如配置文件,采用懒汉式的方法,顾名思义,懒汉么,很懒的,配置文件的实例直到用到的时候才会加载。。。。。。

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. class CSingleton  
  2. {  
  3. public:  
  4. static CSingleton* GetInstance()  
  5. {  
  6.      if ( m_pInstance == NULL )    
  7.          m_pInstance = new CSingleton();  
  8.      return m_pInstance;  
  9. }  
  10. private:  
  11.     CSingleton(){};  
  12.     static CSingleton * m_pInstance;  
  13. };  

GetInstance()使用懒惰初始化,也就是说它的返回值是当这个函数首次被访问时被创建的。这是一种防弹设计——所有GetInstance()之后的调用都返回相同实例的指针:
CSingleton* p1 = CSingleton :: GetInstance();
CSingleton* p2 = p1->GetInstance();
CSingleton & ref = * CSingleton :: GetInstance();
对GetInstance稍加修改,这个设计模板便可以适用于可变多实例情况,如一个类允许最多五个实例。


代码很简单,但是会存在内存泄漏的问题,new出来的东西始终没有释放,下面是一种饿汉式的一种改进。

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. class CSingleton    
  2. {    
  3. private:    
  4.     CSingleton()    
  5.     {    
  6.     }    
  7.     static CSingleton *m_pInstance;    
  8.     class CGarbo     
  9.     {    
  10.     public:    
  11.         ~CGarbo()    
  12.         {    
  13.             if(CSingleton::m_pInstance)    
  14.                 delete CSingleton::m_pInstance;    
  15.         }    
  16.     };    
  17.     static CGarbo Garbo;     
  18. public:    
  19.     static CSingleton * GetInstance()    
  20.     {    
  21.         if(m_pInstance == NULL)    
  22.             m_pInstance = new CSingleton();    
  23.         return m_pInstance;    
  24.     }    
  25. };    

    在程序运行结束时,系统会调用CSingleton的静态成员Garbo的析构函数,该析构函数会删除单例的唯一实例。使用这种方法释放单例对象有以下特征:
1.在单例类内部定义专有的嵌套类。
2.在单例类内定义私有的专门用于释放的静态成员。
3.利用程序在结束时析构全局变量的特性,选择最终的释放时机。


饿汉式

       饿汉式的特点是一开始就加载了,如果说懒汉式是“时间换空间”,那么饿汉式就是“空间换时间”,因为一开始就创建了实例,所以每次用到的之后直接返回就好了。

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. class CSingleton    
  2. {    
  3. private:    
  4.     CSingleton()      
  5.     {    
  6.     }    
  7. public:    
  8.     static CSingleton * GetInstance()    
  9.     {    
  10.         static CSingleton instance;     
  11.         return &instance;    
  12.     }    
  13. };    

      饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的。

注:线程安全的通俗解释 - 不管多个线程是怎样的执行顺序和优先级,或是wait,sleep,join等控制方式,如果一个类在多线程访问下运转一切正常,并且访问类不需要进行额外的同步处理或者协调,那么我们就认为它是线程安全的。 线程安全的类应当封装了所有必要的同步操作,调用者无需额外的同步。还有一点:无状态的类永远是线程安全的。

        

         在饿汉式的单例类中,其实有两个状态,单例未初始化和单例已经初始化。假设单例还未初始化,有两个线程同时调用GetInstance方法,这时执行 m_pInstance == NULL 肯定为真,然后两个线程都初始化一个单例,最后得到的指针并不是指向同一个地方,不满足单例类的定义了,所以饿汉式的写法会出现线程安全的问题!在多线程环境下,要对其进行修改。


多线程下的单例模式

        这里要处理的是懒汉模式。

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. class Singleton  
  2. {  
  3. private:  
  4.     static Singleton* m_instance;  
  5.     Singleton(){}  
  6. public:  
  7.     static Singleton* getInstance();  
  8. };  
  9.   
  10. Singleton* Singleton::getInstance()  
  11. {  
  12.     if(NULL == m_instance)  
  13.     {  
  14.         Lock();//借用其它类来实现,如boost  
  15.         if(NULL == m_instance)  
  16.         {  
  17.             m_instance = new Singleton;  
  18.         }  
  19.         UnLock();  
  20.     }  
  21.     return m_instance;  
  22. }  

使用double-check来保证thread safety.但是如果处理大量数据时,该锁才成为严重的性能瓶颈。
6
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:752953次
    • 积分:8994
    • 等级:
    • 排名:第2304名
    • 原创:45篇
    • 转载:632篇
    • 译文:0篇
    • 评论:55条
    最新评论