单体模式就是保证一个类至始至终只要一个实例,要实现单体必须保证以下几点:
- 构造函数为Private或者Protected
- 析构函数应当为Private或者Protected(没有严格说明)
- 拷贝构造函数和赋值操作符operator=必须为Private或Protected,且只声明不实现(不实现可视情况而定)
C++ 线程安全的单例模式
1. 需要注意的一点,C++中当我们定义了任何一个构造函数(包括拷贝构造函数)时,编译器便不会为我们提供缺省的默认构造函数,但是只要我们没有定义拷贝构造函数,复制操作符operator=以及析构函数时,系统都会为我们提供一个默认的版本。所以不要以为将构造函数设为Private或Protected就万事大吉了,事实并非如此,你必须显示的将复制函数(拷贝构造函数+复制操作符)同时声明为Private或者Protected。
2. 网上没有找到对于析构函数的统一意见,个人认为如果对于那种至始至终都应该存在且只应当初始化一次的单体的应用场景,那们将析构函数设为Protected或者Private很有必要,对于强迫症的朋友,希望一切资源都优雅的释放,那么有两个解决方案,如下:
方案一:提供接口
#include <stdio.h> class singleton{ public: static singleton* instance() { if(NULL == _instance) { _instance = new singleton(); } return _instance; } static void destory() { if(NULL != _instance) { delete _instance; _instance = NULL; } } private: singleton(){printf("create a object of class singleton.\n");} singleton(const singleton&); singleton& operator=(const singleton&); ~singleton(){} private: static singleton* _instance; }; singleton* singleton::_instance = NULL;
该方案假设用户能够正确使用destory接口仅仅在程序退出前调用一次,尽管即使调用多次也不会造成多个实例的存在(单线程),但是会导致实例不一致,可能丢失一些重要信息。也就是说这个依赖于用户的自觉性。但该接口比误用delete的可能性小的多。
方案二:智能指针
<pre name="code" class="cpp">#include <stdio.h> #include <memory> using std::auto_ptr; class singleton{ template <typename T> friend class auto_ptr; //friend class auto_ptr<singleton>; //编译不通过 public: static singleton* instance() { if(NULL == _instance) { _instance = new singleton(); auto_ptr<singleton> tmp(_instance); autoDelete = tmp; } return _instance; } private: singleton(){printf("create a object of class singleton.\n");} singleton(const singleton&); singleton& operator=(const singleton&); ~singleton(){printf("delete a object of class singleton.\n");} private: static singleton* _instance; static auto_ptr<singleton> autoDelete; }; singleton* singleton::_instance = NULL; auto_ptr<singleton> singleton::autoDelete;
这样的话就可以在最后由智能指针来负责释放实例所占资源了,但是这样所有的auto_ptr智能指针都获得了访问单体私有成员的权利,那么还是有可能多次释放,那么是否还有更好的办法呢,若想要更加安全,见下面的方法:
方案三:内部类
#include <stdio.h> class singleton{ public: static singleton* instance() { if(NULL == _instance) { _instance = new singleton(); } return _instance; } private: singleton(){printf("create a object of class singleton.\n");} singleton(const singleton&); singleton& operator=(const singleton&); ~singleton(){printf("delete a object of class singleton.\n");} private: class destory{ public: ~destory() { delete _instance; _instance = NULL; } }; private: static singleton* _instance; static destory release; }; singleton* singleton::_instance = NULL;
这样的话会在程序退出之前释放资源,同时外部没有任何方式调用释放资源的接口,这样安全可靠。
方案四:局部静态成员
#include <stdio.h> class singleton{ public: static singleton* instance() { static singleton _instance; return &_instance; } private: singleton(){printf("create a object of class singleton.\n");} singleton(const singleton&); singleton& operator=(const singleton&); ~singleton(){printf("delete a object of class singleton.\n");} };
这样我们完全不必担心资源的释放问题。