单例模式--含义是某一个类,在一个进程中只有唯一的一个对象

###单例模式
单例模式是一种常见的设计模式
表示的含义是某一个类,在一个进程中只有唯一的一个对象,并且在语法角度上进行制约


###为什么要有单例模式 在系统中,有些类必须保证只能创造出一个对象 我们windows系统中,只能打开一个资源管理器,因为若是可以打开多个资源管理器窗口,就会存在这样的问题: 1.若这些窗口中显示的内容是均相同的,这是一种资源的浪费 2.若这些窗口中显示的内容是不相同的,那么到底哪一个才是正真反应出当前的各个任务状态呢?或者说同一时刻存在两种不同的状态,这怕是与实际不相符吧
###单例模式要点
  • 一个类只能实例化出一个对象
  • 必须由自己进行创建
  • 它必须向整个系统提供访问接口

###单例模式的实现

(方案一)饿汉模式

对象定义后数据立即加载到内存,以空间换时间的做法

class Singleton_1                                                                                                                                              
{                                                                                                                                                              
  public:                                                                                                                                                      
    static Singleton_1 *GetInstance()//静态的成员函数,为外部提供接口                                                                                       
    {                                                                                                                                                          
      return _inst;                                                                                                                                            
    }
  protected:
	  Singleton_1() {};                                                                                                                                                            
  private:                                                                                                                                                                                                                                                                                         
    Singleton_1(const Singleton_1 & ) = delete;                                                                                                                
    Singleton_1 operator = (const Singleton_1 &) = delete;                                                                                                     
    static Singleton_1  *_inst;//静态数据员。在该类范围中只能定义一个                                                                                                                                                                                                                                                                                             
};                                                                                                                                                             
                                                                                                                                                               
//需要先对静态成员进行初始化                                                                                                                                   
Singleton_1  *Singleton_1:: _inst =  new Singleton_1();                                                                                                        
//得到唯一的对象                                                                                                                                               
Singleton_1 * inst_ptr = Singleton_1::GetInstance();  

举例验证

#include <stdio.h>
#include <iostream>
using namespace std;

template <class T>                                                                                                                                             
//类模板                                                                                                                                                       
class Singleton_1                                                                                                                                              
{                                                                                                                                                              
  public:                                                                                                                                                      
    static T *GetInstance()//静态的成员函数,用于访问 T 数据                                                                                                   
    {                                                                                                                                                          
      return _inst;                                                                                                                                            
    }                                                                                                                                                          
                                                                                                                                                               
  private:                                                                                                                                                     
    Singleton_1(const T & ) = delete;                                                                                                                          
    Singleton_1 & operator = (const T &) = delete;                                                                                                             
    static T* _inst;//静态数据员。在该类范围中只能定义一个                                                                                                     
  protected:                                                                                                                                                   
    Singleton_1() {};                                                                                                                                             
    //构造函数设为保护的是为了继承下去                                                                                                                       
    //这里采用静态成员意为 定义多个Signleton对象只能定义出一个T对象                                                                                            
};                                                                                                                                                             
                                                                                                                                                               
                                                                                                                                                               
//需要先对静态成员进行初始化                                                                                                                                   
template<class T>                                                                                                                                              
T *Singleton_1<T>:: _inst = new T();                                                                                                                           
//规定 T 类对象只能通过 Signleton对象定义出来                                                                                                                  
//获得唯一的对象                                                                                                                                               
int main()                                                                                                                                                     
{                                                                                                                                                              
  int * ret_ptr_1 = Singleton_1<int>::GetInstance();                                                                                                           
  int * ret_ptr_2 = Singleton_1<int>::GetInstance();                                                                                                           
  *ret_ptr_2 = 9;                                                                                                                                              
  *ret_ptr_1 = 8;                                                                                                                                              
  printf("ret_1 :%d\n",*ret_ptr_1);                                                                                                                            
  printf("ret_2 :%d\n",*ret_ptr_2);                                                                                                                            
  printf("ret_ptr_1 :%p\n",ret_ptr_1);                                                                                                                         
  printf("ret_ptr_2 :%p\n",ret_ptr_2);                                                                                                                         
  return 0;                                                                                                                                                    
}                 

结果显示:

ret_1 :8
ret_2 :8
ret_ptr_1 :0x12c7c20
ret_ptr_2 :0x12c7c20

饿汉模式是一种线程安全的模式

(方案二)懒汉模式

对象定义出来 先不着急加载到内存,等到第一次使用的时候,再将数据加载到内存,以时间换空间的做法,其实也是一种延时加载

class Singleton_2                                                                                                                                              
{                                                                                                                                                              
  public:                                                                                                                                                      
    static Singleton_2 *GetInstance()                                                                                                                          
    {                                                                                                                                                          
      if(_inst == NULL)                                                                                                                                        
      {//定义的时候先没有开辟空间,只有在用的时候进行调用                                                                                                      
        //多次调用的时候,若不为空可以直接返回                                                                                                                 
        _inst = new Singleton_2();                                                                                                                             
      }                                                                                                                                                        
      return _inst;                                                                                                                                            
    };                                                                                                                                                         
  protected:                                                                                                                                                   
    Singleton_2(){};                                                                                                                                             
  private:                                                                                                                                                     
    static Singleton_2 * _inst;                                                                                                                                
    Singleton_2(const Singleton_2 &) = delete; //防止拷贝                                                                                                      
    Singleton_2 operator = (const Singleton_2 &) = delete; //防止赋值                                                                                          
};                                                                                                                                                             
                                                                                                                                                               
//静态成员需要先进行初始化为NULL                                                                                                                               
Singleton_2 * Singleton_2::_inst = NULL;                                                                                                                       
                                                                                                                                                               
Singleton_2 * inst_ptr= Singleton_2::GetInstance();           

##注意

  1. 这种懒汉单例模式并不是一个线程安全模式,因为在判断_inst是否为空和开辟空间并不是原子操作
  2. 若是两个线程都执行到判断这一步,就会创建两个对象,就会出现逻辑错误
  3. 所以要在判断和创建对象时加上互斥锁
  4. 有为了效率问题,我们只需要在_inst为空的时候再进行加锁
  5. 又为了防止编译器过度优化,我们确保每次判断的时候值都是从内存中读取的,我们需要对私有成员加上 volatile关键字

(方案三)线程安全的懒汉模式


//线程安全的机制的懒汉模式

class Singleton_3
{
  public:
    static pthread_mutex_t lock;

    volatile  static Singleton_3 * GetInstance()
    {
      if(_inst == NULL)
      {
        //每次先判断为空,即还有没开辟空间的时候,在实施线程安全的措施
        //否则的话,每一次调用函数的的时候都判断就太浪费资源了
        pthread_mutex_lock(&lock);
        if(_inst == NULL)
        {
          _inst = new Singleton_3();
        }
        pthread_mutex_unlock(&lock);
      }
      return  _inst;
    }

  protected:
    //在构造函数种对互斥锁进行初始化
    Singleton_3()
    {
      pthread_mutex_init(&lock,NULL);
    };
  private:
    volatile static  Singleton_3 * _inst;
    //防止编译器进行优化
    Singleton_3(const Singleton_3 &) = delete;
    Singleton_3 * operator =(const Singleton_3 &) = delete;
};

//对静态成员的初始化
pthread_mutex_t Singleton_3:: lock ;
volatile Singleton_3 * Singleton_3:: _inst = NULL;


int main()
{
  volatile Singleton_3 * ret_ptr_1  = Singleton_3 ::GetInstance();
  volatile Singleton_3 * ret_ptr_2  = Singleton_3 ::GetInstance();
  volatile Singleton_3 * ret_ptr_3  = Singleton_3 ::GetInstance();

  printf("ret_ptr_1 :%p\n",ret_ptr_1);
  printf("ret_ptr_2 :%p\n",ret_ptr_2);
  printf("ret_ptr_3 :%p\n",ret_ptr_3);

  return 0;
}

结果:

ret_ptr_1 :0xbadc20
ret_ptr_2 :0xbadc20
ret_ptr_3 :0xbadc20
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值