c++单例模式-6种单例层层迭代优化

定义
单例模式(Singleton Pattern,也称为单件模式),使用最广泛的设计模式之一。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。
他应该满足以下几点:

1:确保一个类只有一个实例被建立
2:构造函数应该声明为非公有,从而禁止外界创建实例。
3:拷贝操作和移动操作也应该禁止。
4:提供公有方法获取实例
5:支持多线程

版本1(懒汉)
缺点:
1:没有对资源进行释放
2:不支持多线程

    class Singleton {
    public:
	static Singleton * GetInstance() {
		if (_instance == nullptr) {
			_instance = new Singleton();
		}
		return _instance;
		}
		private:
		Singleton(){}//构造
		Singleton(const Singleton &clone){} //拷⻉构造
		Singleton& operator=(const Singleton&) {}
		stati	c Singleton * _instance;
	}
	Singleton* Singleton::_instance = nullptr;//静态成员需要初始化

版本2
缺点:
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&) {}
		static Singleton * _instance;
	}
	Singleton* Singleton::_instance = nullptr;//静态成员需要初始化

版本3(双重校验锁)
此代码是否感觉很安全,但实际上有重大问题
首先new一个对象时,分为三个步骤,1分配内存 2构造对象 3返回指针。所以常规顺序是123,但是编译器有时候为了优化会指令重排,导致顺序变成132,这里我们考虑这么一种情况
A线程:new1分配内存并按照指令重拍之后的顺序将2地址返回_instance 指针(这时候_instance 指针是非空的,但是还没有到达构造构造,此时时间片用完,线程切换)
B线程进入,此时发现_instance 是非空的,便直接将_instance返回给调用者,而调用着使用这个没有构造的对象将会发生不可预测的后果

指令重拍原因很多,比如编译器优化或者cpu指令流水线导致,具体可以查阅相关资料

    /****************************************
    static Singleton * GetInstance();
    加锁位置:由于除了第一次是需要new,后面调用都只是获取实例,所以在3.1处加锁会极大的损耗性能,故在3.2处通过if判断后才加锁,
    两次if判空原因:主要是考虑多线程环境线程切换因素
    *****************************************/
    #include <mutex>
	class Singleton { // 懒汉模式 lazy load
	public:
	static Singleton * GetInstance() {
		//std::lock_guard<std::mutex> lock(_mutex); // 3.1 切换线程
		if (_instance == nullptr) {
			std::lock_guard<std::mutex> lock(_mutex); // 3.2
			if (_instance == nullptr) {
			_instance = new Singleton();
			atexit(Destructor);
			}
		}
		return _instance;
	}
	private:
		static void Destructor() {
			if (nullptr != _instance) {
				delete _instance;
				_instance = nullptr;
			}
		}
		Singleton(){} //构造
		Singleton(const Singleton &cpy){} //拷⻉构造
		Singleton& operator=(const Singleton&) {}
		static Singleton * _instance;
		static std::mutex _mutex;
	}
	Singleton* Singleton::_instance = nullptr;//静态成员需要初始化
	std::mutex Singleton::_mutex; //互斥锁初始化

版本4
解决版本三问题,但是代码显得很臃肿

    #include <mutex>
	#include <atomic>
	class Singleton {
	public:
		static Singleton * GetInstance() {
			Singleton* tmp = _instance.load(std::memory_order_relaxed);//加载实例
			std::atomic_thread_fence(std::memory_order_acquire);//获取内存屏障
			if (tmp == nullptr) {
				std::lock_guard<std::mutex> lock(_mutex);
				tmp = _instance.load(std::memory_order_relaxed);
				if (tmp == nullptr) {
					tmp = new Singleton;
					std::atomic_thread_fence(std::memory_order_release);//释放内存屏障
					_instance.store(tmp, std::memory_order_relaxed);
					atexit(Destructor);
				}
			}
			return tmp;
		}
	private:
		static void Destructor() {
		Singleton* tmp = _instance.load(std::memory_order_relaxed);
		if (nullptr != tmp) {
			delete tmp;
		}
	}
		Singleton(){}
		Singleton(const Singleton&) {}
		Singleton& operator=(const Singleton&) {}
		static std::atomic<Singleton*> _instance;
		static std::mutex _mutex;
	};
	std::atomic<Singleton*> Singleton::_instance;//静态成员需要初始化
	std::mutex Singleton::_mutex; //互斥锁初始化

版本5
c++11 magic static 特性:如果当变量在初始化的时候,并发同时进⼊声明语句,并发线程将会阻塞等待初始化结束。
缺点:无法继承

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

版本6

    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构造函数
	private:
		DesignPattern(){}
		DesignPattern(const DesignPattern&) {}
		DesignPattern& operator=(const DesignPattern&) {}
	}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@马云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值