C++中的单例模式及按需释放模型(二)

一、在C++中实现单例模式

例子工程的名称是Singleton。

1、模拟C#的方法实现单例模式

本人开始学习设计模式也是先看的C#语言描述的,后来要在C++上实现,参考了网上相关文章,使用一个静态类成员的指针来实现单例模式,代码如下:

SingletonSimulateGC类定义

class SingletonSimulateGC
{
private:
	SingletonSimulateGC(void);
public:
	static SingletonSimulateGC* GetInstance();
	~SingletonSimulateGC(void);

public:	
	int SomeFunction();

private:
	static SingletonSimulateGC *m_pInstance;
};

类实现如下

#include "SingletonSimulateGC.h"

SingletonSimulateGC *SingletonSimulateGC::m_pInstance = NULL;

SingletonSimulateGC* SingletonSimulateGC::GetInstance()
{
	if (m_pInstance == NULL)
	{
		try
		{
			m_pInstance = new SingletonSimulateGC();
		}
		catch (...)		//防止new分配内存可能出错的问题,如果是内存分配错误异常为std::bad_alloc
		{
			m_pInstance = NULL;
		}
	}

	return m_pInstance;
}

SingletonSimulateGC::SingletonSimulateGC(void)
{
}

SingletonSimulateGC::~SingletonSimulateGC(void)
{
}

int SingletonSimulateGC::SomeFunction()
{
	return 10;
}

代码很简单,很像C#的实现,使用静态成员方法GetInstance即可获得一个单例类的实例,这种写法在有垃圾回收机制的语言中是没有问题的,但是C++不行,如果仔细调试的话,会发现直到程序退出SingletonSimulateGC的析构方法都没有被调用过,对于大多数只保存数据的单例类来说,这没有什么,当程序退出的时候,进程会自动释放这些存储空间,但是如果是个设备管理单例类,在这个单例类的析构方法中管理着设备的关闭等清理方法,这个析构方法不被调用,只是进程退出的时候简单的执行一个类似CloseHandle方法,设备是会出现问题的,所以这种做法实际上是错误的。

为了解决这个错误问题,网上有一种做法如下

class CSingleton 
{  
	// 其它成员    
public:    
	static CSingleton * GetInstance()    

private:    
	CSingleton(){};    
	static CSingleton * m_pInstance;    

	class CGarbo // 它的唯一工作就是在析构函数中删除CSingleton的实例    
	{  
	public:  
		~CGarbo()  
		{    
			if (CSingleton::m_pInstance)  
				delete CSingleton::m_pInstance;  
		}  
	};  

	static CGarbo Garbo; // 定义一个静态成员,在程序结束时,系统会调用它的析构函数  
}; 

定义一个内嵌类来辅助释放单例类的单例实例,这个方法是正确的,但是其实现还没有下面第三种做法简单,实现的效果甚至比下面第三种做法还要差,首先单例类CSingleton对象实例可以延迟创建,但是CGarbo实例是系统启动时创建的,多了一个对象,而且这个类实例不能延迟创建,释放也是在系统退出的时候释放的,并不能在功能模块切换时将单例类实例释放掉,即不能解决本系列博文一开始提到的问题。
2、使用类静态成员实现单例模式

SingletonUseStaticClassMember类定义

class SingletonUseStaticClassMember
{
private:
	SingletonUseStaticClassMember(void);
public:
	static SingletonUseStaticClassMember* GetInstance();
	~SingletonUseStaticClassMember(void);

public:	
	int SomeFunction();

private:
	static SingletonUseStaticClassMember m_oInstance;

	int m_i;
};

类实现如下

#include "SingletonUseStaticClassMember.h"

SingletonUseStaticClassMember SingletonUseStaticClassMember::m_oInstance;

SingletonUseStaticClassMember* SingletonUseStaticClassMember::GetInstance()
{
	return &m_oInstance;
}

SingletonUseStaticClassMember::SingletonUseStaticClassMember(void)
{
}

SingletonUseStaticClassMember::~SingletonUseStaticClassMember(void)
{
	m_i = 10;
}

int SingletonUseStaticClassMember::SomeFunction()
{
	return 10;
}

在单例类中定义一个本类的静态成员,这种方式实例类的析构函数会被调用,一切都是正确的,但是这种方式很不好,不能够延迟创建实例类,实际上相当于系统定义了一个全局的类变量,生存期同应用程序一样,从这个角度看甚至还不如第一种做法。

3、使用函数的静态变量实现单例模式

SingletonUseStaticFunctionVariable类定义

class SingletonUseStaticFunctionVariable
{
private:
	SingletonUseStaticFunctionVariable(void);
public:
	static SingletonUseStaticFunctionVariable* GetInstance();
	~SingletonUseStaticFunctionVariable(void);

	int m_i;
public:	
	int SomeFunction();
};

类实现如下

#include "SingletonUseStaticFunctionVariable.h"

SingletonUseStaticFunctionVariable* SingletonUseStaticFunctionVariable::GetInstance()
{
	static SingletonUseStaticFunctionVariable oInstance;

	return &oInstance;
}

SingletonUseStaticFunctionVariable::SingletonUseStaticFunctionVariable(void)
{
	m_i = 5;
}

SingletonUseStaticFunctionVariable::~SingletonUseStaticFunctionVariable(void)
{
	m_i = 10;
}

int SingletonUseStaticFunctionVariable::SomeFunction()
{
	return 10;
}

类定义里不包含类的实例变量或者指针,只在GetInstance方法中使用

	static SingletonUseStaticFunctionVariable oInstance;

方法定义一个实例类的静态变量,多次调用GetInstance方法得到的都是同一个实例,这样就实现了单例,可以做到延迟创建,只有第一次调用GetInstance方法时才创建,并且单例类的析构方法在应用退出时可以被正确调用,这个是C++中实现单例模式比较好的方法。

4、使用单例类的例子

代码如下

#include "stdafx.h"
//#include "./Singleton/SingletonSimulateGC.h"
//#include "./Singleton/SingletonUseStaticClassMember.h"
#include "./Singleton/SingletonUseStaticFunctionVariable.h"
#include <iostream>
#include <ostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	char c;
	int i;
	{
		//SingletonSimulateGC *pSingleton = SingletonSimulateGC::GetInstance();
		//SingletonUseStaticClassMember *pSingleton =
		//	SingletonUseStaticClassMember::GetInstance();
		SingletonUseStaticFunctionVariable *pSingleton =
			SingletonUseStaticFunctionVariable::GetInstance();
		i = pSingleton->SomeFunction();
	}

	cout << i << endl;
	cin >> c;
	return 0;
}

运行结果很简单,就输出一个10,是SomeFunction的返回结果,这里使用大括号控制生命周期,如果你在_tmain的

	return 0;

和SingletonUseStaticFunctionVariable类的析构方法

	m_i = 10;

上都加上断点,你会发现,SingletonUseStaticFunctionVariable的实例指针pSingleton退出大括号的范围并没有释放,先执行_tmain的return语句,后执行的SingletonUseStaticFunctionVariable类的析构方法,也就是单例类的释放总是在程序退出时才被调用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值