C++单例模式

C++ 单例模式实现过程的演变

版本1:

class Singleton
{
	public:
		static Singleton*GetInstance()
		{
			if(_instance == nullptr)
			{
				_instance = new Singleton();
				atexit(Destructor);
			}
			return _instance;
		};
	~Singleton(){};
	private:
		static void Destructor() {
			if (nullptr != _instance) { //
				delete _instance;
				_instance = nullptr;
				}
			}
	Singleton();//构造
	Singleton(const Singleton &cpy); //拷⻉构造
	Singleton& operator=(const Singleton& other) {}
	static Singleton * _instance;
}
Singleton* Singleton::_instance = nullptr;//静态成员需要初始化

显而易见我们的单例模式存在线程安全的问题

版本2

class Singleton
{
	public:
		static Singleton*GetInstance()
		{
		 	std::lock_guard<std::mutex> lock(_mutex); 
			if(_instance == nullptr)
			{
				//std::lock_guard<std::mutex> lock(_mutex);//2.1错误
				_instance = new Singleton();
				atexit(Destructor);
			}
			return _instance;
		};
	~Singleton(){};
	private:
		static void Destructor() {
			if (nullptr != _instance) { //
				delete _instance;
				_instance = nullptr;
				}
			}
	Singleton();//构造
	Singleton(const Singleton &cpy); //拷⻉构造
	Singleton& operator=(const Singleton& other) {}
	static Singleton * _instance;
	static std::mutex _mutex;
}
Singleton* Singleton::_instance = nullptr;//静态成员需要初始化
std::mutex Singleton::_mutex; //互斥锁初始化

在这个版本中我们引用了互斥锁,并且是lock_guard的可以自动释放的互斥锁,但是这里会存在一个性能问题,就是对于任何想要获得单例对象的线程我们都会进行加锁,但是同时只会有一个线程获得,造成大量线程堵塞,然后如果我们将互斥锁的代码写在2.1处,我们会发现这样写还是会有线程不安全的问题

版本3

class Singleton
{
	public:
		static Singleton*GetInstance()
		{
			if(_instance == nullptr)
			{
				std::lock_guard<std::mutex> lock(_mutex);
				if(_instance ==nullptr)
				{
					_instance = new Singleton();
					atexit(Destructor);
				}
			}
			return _instance;
		};
	~Singleton(){};
	private:
		static void Destructor() {
			if (nullptr != _instance) { //
				delete _instance;
				_instance = nullptr;
				}
			}
	Singleton();//构造
	Singleton(const Singleton &cpy); //拷⻉构造
	Singleton& operator=(const Singleton& other) {}
	static Singleton * _instance;
	static std::mutex _mutex;
}
Singleton* Singleton::_instance = nullptr;//静态成员需要初始化
std::mutex Singleton::_mutex;

这个版本的单例模式虽然可以有效的避免多线程之间的问题,同时效率也是挺高的,但是在new的过程中由于cpu reorder的操作,new的执行顺序可能不是按 1. 分配内存 2. 调用构造函数 3. 返回指针 这样的顺序来执行的,有可能是先返回的指针然后调用的构造函数,这样的操作会让多线程的单例模式变得不安全

版本四

class Singleton
{
public:
	static Singleton& GetInstance() {
		static Singleton instance;
		return instance;
	}
private:
	Singleton(){}
	~Singleton() {}
	Singleton(const Singleton&) {}
	Singleton& operator=(const Singleton&) {}
};

利用静态成员变量在c++11 magic static 特性:如果当变量在初始化的时候,并发同时进⼊声明语句,并发线程将会阻塞等待初始化结束。这样可以确保单例模式只会被调用一次,该初始化方式有四大优点1. 利⽤静态局部变量特性,延迟加载;2. 利⽤静态局部变量特性,系统⾃动回收内存,⾃动调⽤析构函数;3. 静态局部变量初始化时,没有 new 操作带来的cpu指令reorder操作;4. c++11 静态局部变量初始化时,具备线程安全;

版本5- 在版本四的基础上声明模板类

template<typename T>
class Singleton {
public:
static T& GetInstance() {
	static T instance; // 这⾥要初始化DesignPattern,需要调⽤DesignPattern构造函数,同时会调⽤⽗类的构造函数。
	return instance;
	}
protected:
	virtual ~Singleton() {}
	Singleton() {} // protected修饰构造函数,才能让别⼈继承
	Singleton(const Singleton&) {}
	Singleton& operator =(const Singleton&) {}
};
class DesignPattern : public Singleton<DesignPattern> {
	friend class Singleton<DesignPattern>; // friend 能让Singleton<T> 访问到DesignPattern构造函数
public:
	~DesignPattern() {}
private:
	DesignPattern() {}
	DesignPattern(const DesignPattern&) {}
	DesignPattern& operator=(const DesignPattern&) {}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值