单例模式的懒汉模式和饿汉模式

单例模式:
要求:
1、单例类只有唯一一个实例对象
2、单例类提供唯一获取这一实例接口GetInstance()
重点:解决线程安全问题

设计难点:
一、饿汉模式(编译加载阶段完成初始化实例):
只需设计一个GetInstance()方法,并直接初始化唯一实例对象(可在方法外初始化也可在方法内初始化)。
二、懒汉模式(在运行时初始化实例):
1、在运行时第一次调用该实例时再初始化。
2、考虑线程安全问题:即初始化时在new前加lock_guard类型的锁,保证new一系列操作的原子性,该锁必须定义为static,保证所有线程用一把锁。RAII 该锁出作用域自动释放。
3、考虑内存优化问题:内存优化可能打乱new的几个步骤的顺序,使用内存栅栏MemoryBarrier()解决该问题。
4、定义一个内部类,在作用域结束前调用该类对象,从而调用该对象的析构,释放单例对象,保证内存不泄露的问题。
共同设计难点:
1、必须将构造、拷贝构造、operator=写在private限定符内,后两个只声明不实现。
2、必须将唯一实例对象和GetInstance方法定义为static的。

懒汉模式和饿汉模式对比:
懒汉模式:
1、在运行代码时才初始化实例,需要解决线程安全问题。
2、加载速度快,运行获取对象慢
3、写法复杂,但所有场景均使用
饿汉模式:
1、在编译加载时初始化实例,不会产生线程安全问题。
2、加载速度慢,运行获取对象速度快
3、写法简单,但适用性受限(如动态库)

代码实现:

#pragma once
#include<cassert>
#include<mutex>
#include<windows.h>
using namespace std;
//懒汉模式 --- 在运行时创建单例对象
namespace LAZY
{
	class singleton
	{
	public:
		static singleton* GetInstance()
		{
			if (_init == NULL)   //只有第一次创建对象时走一次
			{
				//加锁,保证new和赋值为原子的  RAII----出作用域释放锁
				lock_guard<mutex> lock(_mut);
				
				//new的步骤:
				//1.operator new开空间
				//2.调构造函数
				//3.赋值
				//_init = new singleton;

				//由于内存优化可能将2、3优化顺序颠倒-----采用内存栅栏防止优化
				singleton* tmp = new singleton;
				MemoryBarrier();  //内存栅栏---保证栅栏之前的必定比栅栏之后的先运行
				_init = tmp;
			}
			return _init;
		}
		void print()
		{
			cout << "singleton:" << _a << endl;
		}

		//内部类,完成单例对象的释放工作
		struct GC
		{
			~GC()
			{
				DelInstance();
			}
		};
		static void DelInstance()
		{
			lock_guard<mutex> lock(_mut);
			if (_init != NULL)
			{
				cout << "delete" << endl;
				delete _init;
				_init = NULL;
			}
		}
	private:
		singleton()
			:_a(0)
		{}
		~singleton()
		{
			//释放数据库等操作
		}
		//只声明不实现
		singleton(const singleton&);
		singleton& operator=(const singleton&);

		int _a;
		//定义静态成员和锁
		static singleton* _init;
		static mutex _mut;   //静态锁保证全局是一把锁---保证new和赋值的原子性
	};
	singleton* singleton::_init = NULL;
	mutex singleton::_mut;

	void Test()
	{
		singleton::GetInstance()->print();
		singleton::GetInstance()->print();
		singleton::GetInstance()->print();
		getchar();
	}
	//创建gc对象,出作用域时释放_init
	static singleton::GC gc;
}


//饿汉模式  --- 编译加载时初始化唯一实例对象
namespace HUNGRY
{
	class singleton
	{
	public:
		//获取单例对象必须是静态方法
		static singleton& GetInstance()
		{
			//assert(_init);
			//return *_init;
			
			static singleton _init;  
			return _init;
		}

		void print()
		{
			cout << "singleton:" << _a << endl;
		}
	private:
		singleton()
			:_a(0)
		{}
		//将拷贝构造operator=设置为防拷贝
		singleton(const singleton&);
		singleton& operator=(const singleton&);
		
		int _a;  //单例类成员变量

		//static singleton* _init;
	}; 
	//初始化单例对象
	//singleton* singleton::_init = new singleton;

	void Test()
	{
		singleton::GetInstance().print();
		singleton::GetInstance().print();
		singleton::GetInstance().print();
		getchar();
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值