转载地址:http://blog.csdn.net/lbqbraveheart/article/details/7084509
单件模式应该是所有设计模式中最简单的一个了,但是如果使用不当会出现很多问题,下面我们就分析一下单件模式
作用:保证一个class只有一个实体(instance),并为它提供一个全局唯一的访问点
适用性:
1、对于一个类(对象),如果它比较大(占用的系统资源非常多),而且这些资源可以被全局共享,则可以设计为singleton模式。
2、对于一个类,需要对实例进行计数。可以在Instance中进行,并可以对实例的个数进行限制。
3、对于一个类,需要对其实例的具体行为进行控制,例如,期望返回的实例实际上是自己子类的实例。这样可以通过Singleton模式,对客户端代码保持透明。
首先看一下单件模式的通用写法(注意可能会存在问题的,就看你怎么使用了)
- //设计模式之单件模式
- /*
- 作用:保证一个class只有一个实体(instance),并为它提供一个全局唯一的访问点
- */
- class singleton
- {
- public:
- ~singleton()
- {//析构时使用
- }
- static singleton* getInstance()
- {
- if(_instance == NULL)
- {
- _instance = new singleton();
- }
- return _instance;
- }
- private:
- static singleton *_instance;
- private:
- //最好将所有此类的实例化的进口全部堵死
- singleton()
- {
- }
- singleton(const singleton&)
- {
- }
- singleton& operator=(const singleton &)
- {
- }
- };
- singleton *singleton::_instance = NULL;
使用时,只需要调用singleton::getInstance()既可以获取到singleton的指针使用了,但是需要注意的一点是使用完成后需要调用delete singleton::getInstance();以便释放资源。
我们来分析一下上面的代码:
1、需要手动释放_instance,尤其是做接口时,需要告知使用方调用delete singleton::getInstance();语句。
2、如果在多线程环境下使用,问题更大了,如果大量线程调用到new时,可能会造成内存泄露,并且有可能前后获取的singleton对象不一致。
分析出了上面代码的问题,那我们应如何解决他们?
针对问题1:释放
1、调用delete singleton::getInstance();
2、注册atexit()函数,将释放内存的方法放入到atexit函数中,此种方法可以将多个单件放在一起调用。
- void releasefun()
- {
- delete singleton::getInstance();
- }
- //在使用完成后调用
- atexit(releasefun);
3、使用智能指针,比如STL的auto_ptr,于是我们的singleton变成了:
- //设计模式之单件模式
- /*
- 作用:保证一个class只有一个实体(instance),并为它提供一个全局唯一的访问点
- */
- #include <memory>
- #include <iostream>
- using namespace std;
- class singleton
- {
- public:
- ~singleton()
- {//析构时使用
- }
- static singleton* getInstance()
- {
- if(NULL == _instance.get())
- {
- _instance.reset(new singleton);
- }
- return _instance.get();
- }
- private:
- static auto_ptr<singleton> _instance;
- private:
- //最好将所有此类的实例化的进口全部堵死
- singleton()
- {
- }
- singleton(const singleton&)
- {
- }
- singleton& operator=(const singleton &)
- {
- }
- };
- auto_ptr<singleton> singleton::_instance;
4、利用c++内嵌类和一个静态成员实现自动释放机制。
- //设计模式之单件模式
- /*
- 作用:保证一个class只有一个实体(instance),并为它提供一个全局唯一的访问点
- */
- #include <memory>
- #include <iostream>
- using namespace std;
- class singleton
- {
- public:
- ~singleton()
- {//析构时使用
- }
- static singleton* getInstance()
- {
- if(_instance == NULL)
- {
- static clearer clr;
- _instance = new singleton();
- }
- return _instance;
- }
- private:
- static singleton *_instance;
- private:
- //最好将所有此类的实例化的进口全部堵死
- singleton()
- {
- }
- singleton(const singleton&)
- {
- }
- singleton& operator=(const singleton &)
- {
- }
- class clearer
- {
- public:
- clearer(){}
- ~clearer()
- {
- if(singleton::getInstance())
- {
- delete singleton::getInstance();
- }
- }
- };
- };
- singleton *singleton::_instance = NULL;
针对问题2:多线程版本
引入著名的双检测锁机制
- static singleton* getInstance()
- {
- if(_instance == NULL)
- {
- //加入临界区
- if(NULL == _instance)
- {
- _instance = new singleton();
- }
- //释放临界区
- }
- return _instance;
- }
于是引入了我们的多线程版本:包含两种释放机制上例提到的3\4方法
- //设计模式之单件模式
- /*
- 作用:保证一个class只有一个实体(instance),并为它提供一个全局唯一的访问点
- */
- #include <memory>
- #include <iostream>
- #include <windows.h>
- using namespace std;
- class lockguard
- {
- private:
- CRITICAL_SECTION m_cs;
- public:
- lockguard()
- {
- InitializeCriticalSection(&m_cs);
- }
- ~lockguard()
- {
- DeleteCriticalSection(&m_cs);
- }
- public:
- class cguard
- {
- public:
- cguard(lockguard &lg)
- :m_lg(lg)
- {
- m_lg.guard();
- }
- ~cguard()
- {
- m_lg.unguard();
- }
- private:
- lockguard &m_lg;
- };
- private:
- void guard()
- {
- EnterCriticalSection(&m_cs);
- }
- void unguard()
- {
- LeaveCriticalSection(&m_cs);
- }
- friend class lockguard::cguard;
- };
- class singleton
- {
- public:
- ~singleton()
- {//析构时使用
- }
- private:
- static lockguard _lg;
- static singleton *_instance;
- //static auto_ptr<singleton> _instance;
- private:
- //最好将所有此类的实例化的进口全部堵死
- singleton()
- {
- }
- singleton(const singleton&)
- {
- }
- singleton& operator=(const singleton &)
- {
- }
- class clearer
- {
- public:
- clearer(){}
- ~clearer()
- {
- if(singleton::getInstance())
- {
- delete singleton::getInstance();
- }
- }
- };
- public:
- static singleton* getInstance()
- {
- if(_instance == NULL)
- {
- lockguard::cguard gd(_lg);
- if(NULL == _instance)
- {
- static clearer clr;
- _instance = new singleton();
- }
- }
- /*if(NULL == _instance.get())
- {
- _instance.reset(new singleton);
- }*/
- return _instance;
- //return _instance.get();
- }
- };
- singleton *singleton::_instance = NULL;
- lockguard singleton::_lg;
- //auto_ptr<singleton> singleton::_instance;