[关闭]
@zhengyuhong 2017-02-07T12:21:17.000000Z 字数 2607 阅读 1222

C++单例模式

wiki posts


单例模式

单例模式作用是保证一个类仅有一个实例,并提供一个全局的访问接口,该实例能被所有程序模块共享。

C++单例模式实现方法

实现方法基本是将构造函数私有化,用户访问唯一实例的方法只有get_instance()静态成员函数。

版本1、

  1. class Singleton
  2. {
  3. private:
  4. static Singleton* m_instance;
  5. Singleton(){}
  6. Singleton(const Singleton& other);//拷贝构造函数
  7. Singleton& operator= (const Singleton& other);//重载赋值函数
  8. public:
  9. static Singleton* get_instance();
  10. };
  11. Singleton* Singleton::m_instance = NULL;//静态成员外部初始化
  12. Singleton* Singleton::getInstance(){
  13. if(NULL == m_instance){
  14. m_instance = new Singleton;
  15. }
  16. return m_instance;
  17. }

上述单例模式实现方法比较粗糙,实例m_instance 使用new分配实例,但未安全地delete释放内存,最大问题是多线程环境下不安全,多线程中会同时进入,生成实例。

  1. if(NULL == m_instance){
  2. m_instance = new Singleton;
  3. }

版本2

  1. class Singleton {
  2. private:
  3. static Singleton* m_instance;
  4. Singleton(){}
  5. Singleton(const Singleton& other);//拷贝构造函数
  6. Singleton& operator= (const Singleton& other);//重载赋值函数
  7. public:
  8. static Singleton* get_instance();
  9. };
  10. Singleton* Singleton::m_instance = NULL;//静态成员外部初始化
  11. Singleton* Singleton::getInstance(){
  12. lock();//可以使用pthread.h加入互斥锁
  13. if(NULL == m_instance){
  14. m_instance = new Singleton;
  15. }
  16. unlock();
  17. return m_instance;
  18. }

加入了锁机制,可以互斥访问实例,但是每一次访问接口都需要获取锁,在多线程高并发情况下,这个获取锁会造成阻塞资源浪费。

版本3

  1. class Singleton {
  2. private:
  3. static Singleton* m_instance;
  4. Singleton(){}
  5. Singleton(const Singleton& other);//拷贝构造函数
  6. Singleton& operator= (const Singleton& other);//重载赋值函数
  7. public:
  8. static Singleton* get_instance();
  9. };
  10. Singleton* Singleton::m_instance = NULL;//静态成员外部初始化
  11. Singleton* Singleton::getInstance(){
  12. if(NULL != m_instance){
  13. return m_instance;
  14. }
  15. lock();//可以使用pthread.h加入互斥锁
  16. if(NULL == m_instance){
  17. m_instance = new Singleton;
  18. }
  19. unlock();
  20. return m_instance;
  21. }

单例模式的实例仅初始化一次,那么使用一个双重判断来避免锁是一个nice trick,只会初始化之前才会进入临界区,初始化后,就不再需要进入临界区,直接返回实例指针。
现在多线程安全问题解决了,但是m_instance指向内存的释放问题尚未解决。在C++中,系统会自动析构所有的全局变量以及所有的类的静态成员变量。利用这个类的静态成员变量的自动析构就很好解决了。

版本4

  1. class Singleton {
  2. private:
  3. static Singleton* m_instance;
  4. class GC //作用是在析构函数中释放m_instance指向的内存
  5. {
  6. public:
  7. ~GC() {
  8. if(CSingleton::m_pInstance){
  9. delete Singleton::m_instance;
  10. }
  11. }
  12. };
  13. static GC gc; //结束退出时系统会自动调用它的析构函数
  14. Singleton(){}
  15. Singleton(const Singleton& other);//拷贝构造函数
  16. Singleton& operator= (const Singleton& other);//重载赋值函数
  17. public:
  18. static Singleton* get_instance();
  19. };
  20. Singleton* Singleton::m_instance = NULL;//静态成员外部初始化
  21. Singleton* Singleton::getInstance(){
  22. if(NULL != m_instance){
  23. return m_instance;
  24. }
  25. lock();//可以使用pthread.h加入互斥锁
  26. if(NULL == m_instance){
  27. m_instance = new Singleton;
  28. }
  29. unlock();
  30. return m_instance;
  31. }

现在有了一个GC垃圾收集器,就可以很好地回收了单例m_instance指向的内存了。

版本5

  1. class Singleton {
  2. private:
  3. Singleton(){}
  4. Singleton(const Singleton& other);//拷贝构造函数
  5. Singleton& operator= (const Singleton& other);//重载赋值函数
  6. public:
  7. static Singleton* get_instance();
  8. };
  9. Singleton Singleton::m_singleton;//静态成员外部初始化
  10. Singleton* Singleton::getInstance(){
  11. static Singleton singleton;
  12. return &singleton;
  13. }

系统会自动析构静态成员变量,那么在函数内使用静态变量使得代码简洁有效。且静态实例初始化在程序开始时进入主函数之前就由主线程以单线程方式完成了初始化,不必担心多线程问题。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注