设计模式---单例模式


一、设计原则

  • 依赖倒置原则
    • 高层模块不应该依赖底层模块,二者都应该依赖抽象
    • 抽象不应该依赖具体实现,具体实现应该依赖与抽象
  • 开放封闭原则
    • 一个类应该对扩展开放,对修改关闭
  • 面向接口编程
    • 不将变量类型声明为某个特定的具体类,而是声明为某个接口
    • 客户程序无需获知对象的具体类型,只需要知道对象所具有的接口
    • 减少系统中各部分的依赖关系,从而实现“高内聚,低耦合”的设计方案
  • 封装变化点
    • 将稳定点和变化点分离,扩展修改变化点,让稳定点与变化点的实现层次分离
  • 单一职责原则
    • 一个类应该仅有一个引起它变化的原因
  • 里氏替换原则
    • 子类必须能够替换它的父类型;
    • 错误:主要出现在子类覆盖父类实现,原来使用父类型的程序可能出现错误;覆盖了父类方法却没实现父类方法的职责
  • 接口隔离原则
    • 不应该强迫客户依赖于他们不用的方法
    • 一般用于处理一个类拥有比较多的接口,而这些接口涉及到很多职责
  • 对象组合优先类继承
    • 继承耦合度高,组合耦合度低

二、单例模式

1.定义

保证⼀个类仅有⼀个实例,并提供⼀个该实例的全局访问点

2.代码

版本1:有内存泄露和线程不安全的问题

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

版本2:// 还可以使⽤ 内部类,智能指针来解决; 此时还有线程安全问

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.1:粒度太大
版本3.2:也有问题,new + 赋值 不是原子操作 第一个_instance可能不为空 但是还没有创建出来

#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; //互斥锁初始化
// g++ Singleton.cpp -o singleton -std=c++11

版本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:居于版本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构造函数
private:
 	DesignPattern(){}
 	DesignPattern(const DesignPattern&) {}
 	DesignPattern& operator=(const DesignPattern&) {}
}

总结

C++ magic static 完美解决单例模式的内存泄漏和线程安全问题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值