设计模式-单例模式

单例模式

单例一般应用于全局中只需要一个该对像的情况, 自己创建自己并提供了该类的唯一访问接口。
一.懒汉式实现,
(1)该模式下选哟注意线程安全问题。使双检锁(DCLP)。

class SingletonLazy
{
	private: 
			SingletonLazy(){};
			static SingletonLazy* m_instance;
			static std::mutex     m_mutex;
			SingletonLazy(const SingletonLazy&); //防止拷贝构造
			SingletonLazy& operator = (const SingletonLazy&); //防止赋值运算符拷贝对象
			~SingletonLazy(){}; //防止外界delete;
	public:
			//手动删除单例
			static void DestroySingleton()
			{
				delete m_instance;
			}
			static SingletonLazy* Get_instance()
			{
				if(m_instance == nullptr)   //双重判断提高效率,避免每次调用Get_instance都进行一次加解锁
				{
					std::lock_guard<std::mutex> lgard(m_mutex);
					if(m_instance == nullptr)
					{
						m_instance = new SingletonLazy();
					}
				}
				return m_instance;
			}
};
SingletonLazy* SingletonLazy::m_instance = NULL;  
std::mutex SingletonLazy:: m_mutex; 

注意:由于编译器的实现不同,双检锁有时会失效。 例如:SingletonLazy = new SingletonLazy(), 在编译时这句代码分为三步
1 分配内存空间以保存单例对象。

2 在分配的内存中构造一个单例对象。

3 使m_instance指向分配的内存。
第二步和第三步顺序可能颠倒。 如果一个线程调用Get_instance该函数,代码走到m_instance = new SingletonLazy()这步时, 先给m_instance指向分配的内存,而没有进行对象的构造。此时又有一个线程访问Get_insatnce函数,此时m_instance已经不是空的了,返回实例给对方,由于此时实例没有构造出来,就会出现问题。

C++11给出了双检锁失效的解决办法, 使用原子操作

class SingletonLazy
{
	private: 
			SingletonLazy(){};
			static  std::atomic<SingletonLazy*> m_instance;
			static std::mutex     m_mutex;
			SingletonLazy(const SingletonLazy&); //防止拷贝构造
			SingletonLazy& operator = (const SingletonLazy&);//防止赋值运算符拷贝对象
			~SingletonLazy(); //防止外界delete;
	public:
			//手动删除单例
			static void DestroySingleton()
			{
				delete m_instance;
			}
			static SingletonLazy* Get_instance()
			{
				SingletonLazy* tmp = m_instance.load(std::memory_order_relaxed);
				std::atomic_thread_fence(std::memory_order_acquire); //获取屏障								
				if(tmp == nullptr)   
				{
					std::lock_guard<std::mutex> lgard(m_mutex);
					tmp = m_instance.load(std::memory_order_relaxed); 
					if(tmp == nullptr)
					{
					
						tmp = new SingletonLazy();
						std::atomic_thread_fence(std::memory_order_relaxed); //释放屏障
						m_instance.store(tmp, std::memory_order_relaxed);
					}
				}
				return tmp;
			}
			
};
std::atomic<SingletonLazy*> SingletonLazy::m_instance = NULL;  
std::mutex SingletonLazy:: m_mutex; 

(2)还有一种懒汉式实现,是使用局部静态变量的方法

class SingletonLazy
{
	private: 
			SingletonLazy(){};
			SingletonLazy(const SingletonLazy&); //防止拷贝构造
			SingletonLazy& operator = (const SingletonLazy&);//防止赋值运算符拷贝对象
	public:
			~SingletonLazy() {};
			static SingletonLazy* Get_instance()
			{
				static SingletonLazy instance;
				return &instance;
			}
}

这种方法叫做 Meyers’ SingletonMeyer’s的单例, 《Effective C++》系列书籍的作者 Meyers 提出的。当变量在初始化时 ,并发进入声明语句时,并发线程将会阻塞,等待初始化结束。由于是静态变量,只初始化一次,声明时又线程安全。所以不必加锁。推荐懒汉式这样实现
(3)单例模式也可以用饿汉式实现

class SingletonLazy
{
	private: 
			SingletonLazy();
			static SingletonLazy m_instance;
			SingletonLazy(const SingletonLazy7); //防止拷贝构造
			SingletonLazy& operator = (const SingletonLazy&); //防止赋值运算符拷贝对象
			~SingletonLazy(); //防止外界delete;
	public:
			static SingletonLazy* Get_instance()
			{
				return &m_instance;
			}
}
SingletonLazy SingletonLazy::m_instance;

该模式下程序一开始对象就生成了,如果一直没有用到,就会造成一定的内存浪费。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值