单例模式之懒汉模式与饿汉模式

单例模式

概念:一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所以程序模块共享

单例模式下分为饿汉模式和懒汉模式两种

 

饿汉式

无论将来用不用这个对象,程序启动时就创建一个唯一的实例对象

场景:适合与创建对象消耗资源少且使用活跃的情况(对性能要求高)

特性:程序启动慢,如果存在多个单例对象的创建,创建的顺序将不确定

创建过程:

  1. 声明一个静态对象指针
  2. 在程序入口之前就完成对单例模式的初始化
  3. 私有化构造函数(拷贝构造、赋值运算符重载)
  4. 要注意使用过后对资源的回收
class Singleton {
public:      
	static Singleton* GetInstance() 
	{ 
		return &m_instance; 
	}    
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 m_instance;  
};  

// 在程序入口之前就完成单例对象的初始化
Singleton Singleton::m_instance;  

 

 

懒汉式:

当需要用到对象的时候再进行创建(延迟加载)

场景:适用于构造对象需要占用大量资源或者非常耗时的情况

特性:进程启动无负载,多个单例对象的创建顺序可以自由控制

构建方式:

  1. 私有化一个静态对象指针
  2. 有一个获取这个对象的唯一公有方法来构造对象
  3. 私有化构造(拷贝构造、赋值运算符重载)
  4. 内嵌一个垃圾回收类(当该对象析构的时候自动销毁该静态指针)

要注意在创建对象的时候一定要进行双重检查对象已经创建

#include <iostream> 
#include <mutex> 
#include <thread> 
using namespace std;

class Singleton {
public:    
	static Singleton* GetInstance() {        
		// 注意这里一定要使用Double-Check的方式加锁,才能保证效率和线程安全 
		//第一处check为了效率
		if (nullptr == m_pInstance) {            
			m_mtx.lock();    
			//第二处check为了安全
			if (nullptr == m_pInstance) {
                try(){
                    m_pInstance = new Singleton();
                    if(m_pInstance == nullptr)
                        throw "instance fail";
                }
                catch(...)
                {
                    //异常处理应当解锁,否则将会形成死锁的情况
                    m_mtx.unlock();
                    cout << "new fail" << endl;
                    return NULL;
                }
			}         
			m_mtx.unlock();
		}        
		return m_pInstance;    
	}

// 实现一个内嵌垃圾回收类        
	class CGarbo {    
	public:        
	~CGarbo()
	{            
		if (Singleton::m_pInstance)                
			delete Singleton::m_pInstance;       
	}    
	};

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

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

	// 防拷贝    
	Singleton(Singleton const&);    
	Singleton& operator=(Singleton const&);
	
	// 单例对象指针    
	static Singleton* m_pInstance; 
	//互斥锁 
	static mutex m_mtx;
};

	Singleton* Singleton::m_pInstance = nullptr; 
	Singleton::CGarbo Garbo; 
	mutex Singleton::m_mtx;
    //这里的创建对象的方式还有以下两种形式
	//方式二:范围锁,如果new出现异常不会导致死锁
	static CSingleton* GetInstance()
	{
		if (Instance == nullptr)
		{
			lock_guard<mutex> lc(lock);
			Instance = new CSingleton();//在范围锁这里不用异常处理,因为不会导致死锁
		}
		return Instance;
	}
	//方法三:内存栅栏
	static CSingleton* GetInstance()
	{
		if (Instance == nullptr)
		{
			lock_guard<mutex> lc(mutex);
			CSingleton* temp = new CSingleton();
            
            //内存栅栏,new分为三步
            //1,开辟空间,2,调用构造函数,3,赋值给instance
			MemoryBarrier();
			
            //但是有些编译器会出现优化,先赋值
            //在调用构造函数,可能会出错误,然后就用MemoryBarrier();
            //如果失败了和instance也没有关系,
			Instance = temp;
		}
		return Instance;
	}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值