现在的位置: 首页 > 综合 > 正文

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

2013年12月20日 ⁄ 综合 ⁄ 共 2492字 ⁄ 字号 评论关闭

关键字:C++、单例模式、友元、模板、多线程、对象生命周期

 

单例模式是设计模式中最简单最容易理解的模式之一,实用方便,项目设计开发中会被经常使用,但是不知道读者有没有考虑过这个问题,单例模式实例什么时候被释放,读者有兴趣可以仔细分析下,按照目前通常方法实现的单例模式都是直到系统退出的时候才释放的,甚至是有垃圾回收机制的C#上也是这样的,系统切换了功能模块还存在大量的这个模块根本不使用的单例类对象,实际上是很浪费存储空间的,单例类少还好说,如果单例类有几十甚至几百的时候(中大型项目这个数量不算夸张),这种空间占用就不是可以轻易容忍的了。

注意我这里说的不仅仅是安全释放的问题(目前网上的关于单例释放的解决方案大多都是安全释放,即程序退出时安全释放),而是能在程序运行中把本模块不用的(其他模块使用的)单例类及时从内存中释放掉。

如果读者觉得这是个问题,并且也想解决这个问题,可以仔细阅读下本系列博文,会对你解决这个问题有帮助的。

 

为了描述单例模式及其问题,首先举一个实际项目的例子,项目是一个手机的移动项目,需要访问硬件设备读取IC卡的内容,读取到的内容需要传递给界面模块显示,这些信息是和人相关的信息,相应的界面主要显示和人业务相关的内容,这些人业务通常需要提供类似民族的下拉列表框方便用户选择民族输入,同时项目中除了管理人业务,还有其他的类似部门管理、仓储货品管理等功能。

简单分析这个项目,发现其中有以下元素可以定义成单例模式对象

1、硬件访问类,因为硬件只有一个,多个对象实例没有意义,而且容易访问冲突;

2、IC卡信息传递类,通过硬件访问到的IC卡信息要么通过结构体作为参数在各个函数中传递,要么定义成单例类直接可以在多个模块访问,不作为函数的参数满天飞,因为硬件只有一个,所以这个类实例存在多个也没有多少意义,所以最好是一个单例类;

3、民族等字典类,这种类在多个模块中使用,也使用单例模式,因为内容是固定的,多个实例只会浪费存储空间。

下边我们分析下3个单例类的区别

1、硬件访问类,管理一个设备,以行为方法为主,数据信息少,而且这种指明设备信息的内容基本不变,对于设备的初始化和关闭的行为,一种方式提供Init、Close等类似方法让外部调用管理,更好的方法是让设备管理类成为一个闭包,在构造函数和析构函数中执行初始化和关闭的行为,即最好是闭包的单例类管理设备(关于这一点,很多教科书会说构造函数的行为要尽量简单,不要执行一些实际的可能错误的行为,还是使用Init、Close的方式比较好,但是即使是这样,安全的做法也应该在析构函数中调用Close方法,提供一个最后的安全关闭能力);

2、IC卡信息传递类,内容或者说内部各个字段的状态是可变的,每次写入读取都会变化,即有状态的单例类;

3、民族等字典类,内容可以认为恒定不变的,类似的字典类可能很多,比如行政区划也是这种类,如果不在人业务中,不会使用这种字典类,如果在其他不使用这些字典单例类实例的模块中运行时,这些单例类还存在就会浪费存储空间,最好能在确认不使用的情况下把内容释放掉,即状态不变需要释放的单例类。(关于这一点其实还有个方法就是模块划分清晰的话做成DLL,那样当人业务DLL卸载的时候,其中的字典表自然就不会存在了,但是这要求DLL划分的粒度够小,毕竟很难做到所有字典表同DLL直接对应好,所以存在按需施放还是有必要的)

对于以上3个单例类,要解决其中讲到的所有情况,单例类应该具有以下特点:

1、必须单例,整个系统只能有一个这种类的实例,不能多个;

2、延迟创建,第一次需要的时候创建,目前的单例模式实现方式大多可以做到这点;

3、按需释放,在确认不使用的情况下,能把单例类释放掉,释放出其占有的内存空间,不是要等到程序退出时才释放。

 

本系列博文会在C++上实现单例模式,并讲解如何让单例类3个特点都具备,网上的单例模式文章很多,主要以java和C#为主,C++的文章也有一些很不错,大家可以自己参考 。

以下是各章节的简单介绍,读者可以根据自己的水平与兴趣选择阅读:

1、C++中的单例模式及按需释放模型(二)中会讲到3种C++中常见的实现单例模式的方法,其中一种是模仿C#编写的,会说明这种方法是错误的,第二种单例模式是正确的,但是非常不好,第三种是目前网上比较常见的正确的实现方法,但是还是不能解决按需释放的问题;

2、C++中的单例模式及按需释放模型(三)中会讲解如何使用辅助类实现按需施放的单例模式,能够实现单例类所有3个特点;

3、C++中的单例模式及按需释放模型(四)中会使用模板类把辅助类抽象出来,变成通用的辅助类,在这一章会发现使用这个辅助模板类的情况下,单例类的开发比平时看到的单例类实现还要简单;

4、C++中的单例模式及按需释放模型(五)中会提供辅助模板类的多线程版本,并演示如何在多线程中使用这种单例类,同时会测试多线程下使用的效率,讲解运行中产生的比较有意思结果的原因。

当读者阅读完本文,读者会发现使用文中的方法实现单例模式更加简单,并且可以实现单例类的全部3种特点。

同时文中会提到使用这个方法还是有个要求的,就是开发者要对对象的生命周期有个比较好的控制能力。

 

值得一提的是,目前java和C#上常见的单例实现方法也不能做到第3种特点,没有这个特点,设备管理类的闭包关闭和常用字典类的按需释放是做不到的。(当然如果开发者觉得不喜欢使用设备的闭包管理、觉得计算机空间是无限的,或者单例占有的空间很小的,不需要按需施放,继续使用常见的单例模式也无不可)

最后说明下文中的示例代码地址是http://download.csdn.net/detail/gogogo/3852925,在vs2005下编译通过,需要的读者可以下载查看。

 

为了使本模型使用起来更加方便,本人后来又对现有的程序进行了改进,主要是进行了操作符重载,使开发过程中使用本模型更加简洁容易,具体请见《按需释放单例模型的改进》,也提供了新的例子,下载地址是http://download.csdn.net/detail/gogogo/3881956

抱歉!评论已关闭.