设计模式—单例模式

设计模式:设计模式是一套被反复使用、多数人知晓、经过分类的、代码设计经验的总结

单例模式:一个类只能创建一个对象,保证系统中该类只有一个实例,并且提供一访问该类资源的访问点。因为有些时候,保持类的实例只有一个是非常必要的。例如:一个表示文件系统的类,一个操作系统一定是只有一个文件系统的。因此,我们就希望表示文件系统的类的实例只有一个

 

单例模式的实现有两种模式:

  • 饿汉模式:就是不管你以后会不会用,程序启动时候都会创建一个唯一的实例对象

  • 懒汉模式:懒汉模式秉承着能够晚一点构造就晚一点构造的思想,直到第一次使用单例时才会创建该类的唯一实例对象。也是延迟加载的一种体现

 

饿汉模式: 

class Singleton
{
public:
       static Singleton* GetInstance()
       {
              return &_instance;
       }  
       int a = 10;

private:
       //构造函数私有
       Singleton()
       {};

       //C++98 防拷贝
       //Singleton(Singleton const&);
       //Singleton& operator=(Singleton const&);

       //or

       //C++11 防拷贝
       Singleton(Singleton const&) = delete;
       Singleton& operator=(Singleton const&) = delete;

       static Singleton _instance;
};

Singleton Singleton::_instance;          //在程序入口前就会完成初始化
  • 优点:实现起来比较简单

  • 缺点:可能会导致进程启动缓慢,并且如果有多个单例类对象实例,各个单例类对象创建顺序不确定

  • 建议用 C++ 11 防拷贝

 

懒汉模式 1.0:

class Singleton  
{
public:
       static Singleton * GetInstance()
       {
              if (nullptr == _pInstance)
              {
                     _pInstance = new Singleton;
              }
              return _pInstance;
       }

private:
       //构造函数私有化
       Singleton()
       {};

       //实现一个内嵌的回收类
       class CGarbo
       {
       public:
              ~CGarbo()
              {
                     if (_pInstance)
                           delete _pInstance;
              }
       };

       //C++ 98 防拷贝
       //Singleton(Singleton const&);
       //Singleton& operator= (Singleton const&);

       //or

       //C++ 11 防拷贝
       Singleton(Singleton const&) = delete;
       Singleton& operator= (Singleton const&) = delete;

       //定义一个静态成员变量,程序结束时调用它的析构函数,从而释放单例类对象
       static CGarbo Garbo;

       static Singleton* _pInstance;            //单例对象指针
};



Singleton* Singleton::_pInstance = nullptr;            //单例类中指针置空

Singleton::CGarbo Singleton::Garbo;                    //内部回收类静态对象初始化

 

  • 因为懒汉模式中的单例类对象实例是new出来的,所以就需要我们用户自己去手动delete去释放资源,因此可以在单例类内部实现一个嵌套的回收类,这个回收类的析构函数来做对单例类对象实例的delete工作,通过在单例类内部定义一个回收类的静态成员变量,当程序结束时调用它的析构函数,从而释放析构类

  • 这种实现在单线程下是没有问题的,但是在多线程的情况下,如果多个线程同时首次去调用GetInstance方法,并且检测到_pInstance是nullptr,则这多个线程将都会new一个实例给_pInstance,这样就会发生错误

 

懒汉模式 1.1 (加互斥锁):

class Singleton  
{
public:
       static Singleton * GetInstance()
       {
              //通过互斥锁保证多线程环境下对于临界资源的访问
              _mtx.lock();  
              if (nullptr == _pInstance)
              {
                     _pInstance = new Singleton;
              }
              _mtx.unlock();

              return _pInstance;
       }

private:
       //构造函数私有化
       Singleton()
       {};

       //实现一个内嵌的回收类
       class CGarbo
       {
       public:
              ~CGarbo()
              {
                     if (_pInstance)
                     {
                           delete _pInstance;
                     }
              }
       };

       //C++ 98 防拷贝
       //Singleton(Singleton const&);
       //Singleton& operator= (Singleton const&);

       //or

       //C++ 11 防拷贝
       Singleton(Singleton const&) = delete;
       Singleton& operator= (Singleton const&) = delete;

       //定义一个静态成员变量,程序结束时调用它的析构函数,从而释放单例类对象
       static CGarbo Garbo;

       static Singleton* _pInstance;            //单例对象指针
       static std::mutex _mtx;           //定义一个静态的互斥锁
};

Singleton* Singleton::_pInstance = nullptr;            //单例类中指针置空
Singleton::CGarbo Singleton::Garbo;                    //内部回收类静态对象初始化
std::mutex Singleton::_mtx;                            //对互斥锁初始化
  • 通过加锁保证临界资源的互斥访问,可以保证线程安全

  • 但是这种加锁方式会导致每次调用GetInstance方法时都会有加锁解锁的消耗,

懒汉模式 1.2 (双重检查锁):

class Singleton  
{
public:
       static Singleton * GetInstance()
       {
              if (nullptr == _pInstance)
              {
                     //通过互斥锁保证多线程环境下对于临界资源的访问
                     _mtx.lock();
                     if (nullptr == _pInstance)
                     {
                           _pInstance = new Singleton;
                     }
                     _mtx.unlock();
              }
              return _pInstance;
       }

private:
       //构造函数私有化
       Singleton()
       {};

       //实现一个内嵌的回收类
       class CGarbo
       {
       public:
              ~CGarbo()
              {
                     if (_pInstance)
                     {
                           delete _pInstance;
                     }
              }
       };

       //C++ 98 防拷贝
       //Singleton(Singleton const&);
       //Singleton& operator= (Singleton const&);

       //or

       //C++ 11 防拷贝
       Singleton(Singleton const&) = delete;
       Singleton& operator= (Singleton const&) = delete;

       //定义一个静态成员变量,程序结束时调用它的析构函数,从而释放单例类对象
       static CGarbo Garbo;
       static Singleton* _pInstance;            //单例对象指针
       static std::mutex _mtx;           //定义一个静态的互斥锁
};

Singleton* Singleton::_pInstance = nullptr;            //单例类中指针置空
Singleton::CGarbo Singleton::Garbo;                    //内部回收类静态对象初始化
std::mutex Singleton::_mtx;                            //对互斥锁初始化
  • 在之前互斥锁保证线程安全的基础上,又新增了一次检查,只在第一次创建的时候进行加锁,当_pInstance不为空时不加锁,减少了不必要的加锁消耗,提高了效率

  • 但是在new失败抛异常以及跳转等情况下可能会导致加锁后造成死锁的情况

 

懒汉模式 1.3 (lock_guard):

class Singleton  
{
public:
       static Singleton * GetInstance()
       {
              if (nullptr == _pInstance)
              {
                     //将互斥锁交给lock_guard去管理,避免因为new抛异常等问题导致加锁后造成死锁
                     std::lock_guard<std::mutex> lck(_mtx);

                     if (nullptr == _pInstance)
                     {
                           _pInstance = new Singleton;
                     }
              }
              return _pInstance;
       }

private:
       //构造函数私有化
       Singleton()
       {};

       //实现一个内嵌的回收类
       class CGarbo
       {
       public:
              ~CGarbo()
              {
                     if (_pInstance)
                     {
                           delete _pInstance;
                     }
              }
       };

       //C++ 98 防拷贝
       //Singleton(Singleton const&);
       //Singleton& operator= (Singleton const&);

       //or

       //C++ 11 防拷贝
       Singleton(Singleton const&) = delete;
       Singleton& operator= (Singleton const&) = delete;
       //定义一个静态成员变量,程序结束时调用它的析构函数,从而释放单例类对象

       static CGarbo Garbo;
       static Singleton* _pInstance;            //单例对象指针
       static std::mutex _mtx;           //定义一个静态的互斥锁
};

Singleton* Singleton::_pInstance = nullptr;            //单例类中指针置空
Singleton::CGarbo Singleton::Garbo;                    //内部回收类静态对象初始化
std::mutex Singleton::_mtx;                            //对互斥锁初始化
  • 基于RAII 的思想将互斥锁交给lock_guard对象去管理,构造时加锁,析构时解锁。因为是临时对象,当函数栈桢结束时便会调用析构解锁,可以有效的避免死锁

懒汉模式版本 2 (静态局部变量):

class Singleton  
{
public:
       static Singleton * GetInstance()
       {
              //静态局部变量
              static Singleton Instance;
              return &Instance;
       }

private:
       //构造函数私有化
       Singleton()
       {};

       //C++98防拷贝
       //Singleton(Singleton const&);
       //Singleton& operator= (Singleton const&);

       //or

       //C++11防拷贝
       Singleton(Singleton const&) = delete;
       Singleton& operator= (Singleton const&) = delete;
};
  • 关于静态局部变量的线程安全: 在C++0x(即C++11)标准中,规定了编译器必须完成static变量的线程安全问题

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值