c++ 设计模式之单件模式

单件模式应该是所有设计模式中最简单的一个了,但是如果使用不当会出现很多问题,下面我们就分析一下单件模式

作用:保证一个class只有一个实体(instance),并为它提供一个全局唯一的访问点

 适用性:

1、对于一个类(对象),如果它比较大(占用的系统资源非常多),而且这些资源可以被全局共享,则可以设计为singleton模式。
2、对于一个类,需要对实例进行计数。可以在Instance中进行,并可以对实例的个数进行限制。
3、对于一个类,需要对其实例的具体行为进行控制,例如,期望返回的实例实际上是自己子类的实例。这样可以通过Singleton模式,对客户端代码保持透明。

首先看一下单件模式的通用写法(注意可能会存在问题的,就看你怎么使用了)

//设计模式之单件模式
/*
作用:保证一个class只有一个实体(instance),并为它提供一个全局唯一的访问点
*/
class singleton
{
public:
	~singleton()
	{//析构时使用
	}
	static singleton* getInstance()
	{
		if(_instance == NULL)
		{
			_instance = new singleton();
		}
		return _instance;
	}

private:
	static singleton *_instance;

private:
//最好将所有此类的实例化的进口全部堵死
	singleton()
	{

	}
	singleton(const singleton&)
	{

	}
	singleton& operator=(const singleton &)
	{

	}
};
singleton *singleton::_instance = NULL;

使用时,只需要调用singleton::getInstance()既可以获取到singleton的指针使用了,但是需要注意的一点是使用完成后需要调用delete singleton::getInstance();以便释放资源。

我们来分析一下上面的代码:

1、需要手动释放_instance,尤其是做接口时,需要告知使用方调用delete singleton::getInstance();语句。

2、如果在多线程环境下使用,问题更大了,如果大量线程调用到new时,可能会造成内存泄露,并且有可能前后获取的singleton对象不一致。

分析出了上面代码的问题,那我们应如何解决他们?

针对问题1:释放

1、调用delete singleton::getInstance();

2、注册atexit()函数,将释放内存的方法放入到atexit函数中,此种方法可以将多个单件放在一起调用。

void releasefun()
{
	delete singleton::getInstance();
}
//在使用完成后调用
atexit(releasefun);


3、使用智能指针,比如STL的auto_ptr,于是我们的singleton变成了:

//设计模式之单件模式
/*
作用:保证一个class只有一个实体(instance),并为它提供一个全局唯一的访问点
*/
#include 
#include 
using namespace std;
class singleton
{
public:
	~singleton()
	{//析构时使用
	}
	static singleton* getInstance()
	{
		if(NULL == _instance.get())
		{
			_instance.reset(new singleton);
		}
		return _instance.get();
	}
private:
	static auto_ptr _instance;

private:
//最好将所有此类的实例化的进口全部堵死
	singleton()
	{

	}
	singleton(const singleton&)
	{

	}
	singleton& operator=(const singleton &)
	{

	}
};
auto_ptr singleton::_instance;

4、利用c++内嵌类和一个静态成员实现自动释放机制。

//设计模式之单件模式
/*
作用:保证一个class只有一个实体(instance),并为它提供一个全局唯一的访问点
*/
#include 
#include 
using namespace std;
class singleton
{
public:
	~singleton()
	{//析构时使用
	}
	static singleton* getInstance()
	{
		if(_instance == NULL)
		{
			static clearer clr;
			_instance = new singleton();
		}
		return _instance;
	}
private:
	static singleton *_instance;
private:
//最好将所有此类的实例化的进口全部堵死
	singleton()
	{

	}
	singleton(const singleton&)
	{

	}
	singleton& operator=(const singleton &)
	{

	}
	class clearer
	{
	public:
		clearer(){}
		~clearer()
		{
			if(singleton::getInstance())
			{
				delete singleton::getInstance();
			}
		}
	};
};
singleton *singleton::_instance = NULL;

针对问题2:多线程版本

引入著名的双检测锁机制

static singleton* getInstance()
{
	if(_instance == NULL)
	{
		//加入临界区
		if(NULL == _instance)
		{
			_instance = new singleton();
		}
		//释放临界区
	}
	return _instance;
}

于是引入了我们的多线程版本:包含两种释放机制上例提到的3\4方法

//设计模式之单件模式
/*
作用:保证一个class只有一个实体(instance),并为它提供一个全局唯一的访问点
*/
#include 
#include 
#include 
using namespace std;

class lockguard
{
private:
	CRITICAL_SECTION m_cs;

public:
	lockguard()
	{
		InitializeCriticalSection(&m_cs);
	}
	~lockguard()
	{
		DeleteCriticalSection(&m_cs);
	}

public:
	class cguard
	{
	public:
		cguard(lockguard &lg)
			:m_lg(lg)
		{
			m_lg.guard();
		}
		~cguard()
		{
			m_lg.unguard();
		}
	private:
		lockguard &m_lg;
	};
private:
	void guard()
	{
		EnterCriticalSection(&m_cs);
	}
	void unguard()
	{
		LeaveCriticalSection(&m_cs);
	}
	friend class lockguard::cguard;
};

class singleton
{
public:
	~singleton()
	{//析构时使用
	}

private:
	static lockguard _lg;
	static singleton *_instance;
	
	//static auto_ptr _instance;

private:
//最好将所有此类的实例化的进口全部堵死
	singleton()
	{

	}
	singleton(const singleton&)
	{

	}
	singleton& operator=(const singleton &)
	{

	}
	class clearer
	{
	public:
		clearer(){}
		~clearer()
		{
			if(singleton::getInstance())
			{
				delete singleton::getInstance();
			}
		}
	};
public:
	static singleton* getInstance()
	{
		if(_instance == NULL)
		{
			lockguard::cguard gd(_lg);
			if(NULL == _instance)
			{
				static clearer clr;			
				_instance = new singleton();
			}
		}
		/*if(NULL == _instance.get())
		{
		_instance.reset(new singleton);
		}*/
		return _instance;
		//return _instance.get();
	}
};
singleton *singleton::_instance = NULL;
lockguard singleton::_lg;
//auto_ptr singleton::_instance;

至此我们的singleton模式基本结束了,这个模式还是包含很多c++深层的知识的。

你可能感兴趣的:(设计模式,C++,学习)