所谓资源就是一旦使用完,就必须将其归还给系统,否则就有你好果子吃。在C++总,常用的资源包括动态分配内存、文件描述符、互斥锁、UI中的字型和笔刷、数据库连接,网络socket等。接下来本文介绍几种管理资源的方式,以解决资源泄露或回收问题。
一、以对象管理资源
假设我们使用一个用来朔模投资行为的程序库,其中各式各样的投资类型继承自一个root class Investment:
class Investment {...}; //投资类型继承体系中的root class
进一步假设,这个程序库通过一个工厂函数供应我们某个特定的Investment对象:
Investment* createInvestment();
上面函数返回一个指针,指向Investment继承体系内的动态分配对象,调用者有责任删除它。假设有个函数f履行了这个责任:
void f()
{
Investment* pInv = createInvestment(); //调用工厂函数
...
delete pInv; //释放pInv所指对象
}
咋一看上面天衣无缝,函数f能够自动删除它从createInvestment获得的投资对象,但是事实上危机重重:
(1)由于疏忽或者后期接收者维护代码导致“...”区域内的一个过早的return语句或goto语句。
(2)“...”区域内的语句抛出异常。
上面的任意情况发生,都会导致因无法执行到delete语句而内存泄露。事实上,函数f中将资源的管理依赖于人治,所以悲剧地发生只是时间问题。
为了解决如上问题,需要将返回的资源放进对象内,以对象来管理资源,当控制流离开f,该对象的析构函数会自动释放那些资源。
1、auto_ptr
许多资源被动态分配于堆上而后被用于单一区块或函数内,资源应该在控制流离开这个区块或函数时被释放,标准程序库提供的auto_ptr正是针对这种形式而设计的特制产品。
auto_ptr是一个“类指针(pointer-like)对象”,也就是所谓的智能指针,其析构函数自动对其所指对象调用delete。下面示范如何使用auto_ptr以避免函数f潜在的资源泄露可能性:
void f()
{
std::auto_ptr pInv(createInvestment());
...
}
函数f中调用工厂函数产生投资对象,并将对象由auto_ptr管理,然后一如既往地使用pInv,在控制流离开函数f时,由auto_ptr的析构函数自动删除pInv。
上面代码中createInvestment返回的资源被当做其管理者auto_ptr的初值,这种方式被称为“资源获得时机便是初始化时机”(Resource Acquisition Is Initialization, RAII)。
需要注意的是:如果通过copy构造函数或copy assignment操作符复制auto_ptr,则其会变成NULL,而复制所得的指针将取得资源的唯一拥有权,也就是只能有一个auto_ptr对象管理资源,比如:
std::auto_ptr pInv1(createInvestment()); //pInv1指向createInvestment返回物
std::auto_ptr pInv2(createInvestment()); //pInv2指向对象,而pInv1被设为NULL
pInv1 = pInv2; //现在pInv1指向对象,而pInv2被设为NULL
受auto_ptr管理的资源必须绝对没有一个以上的auto_ptr同时指向它,这意味着auto_ptr并非管理动态分配资源的神兵利器,比如STL容器就要求其元素发挥“正常的”复制行为,因此就用不上auto_ptr。
2、shared_ptr
auto_ptr的替代方案是“引用计数型智能指针”(referece-counting smart pointer, RCSP)。所谓RCSP也是个智能指针,持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源。RCSP提供的行为类似垃圾回收(garbage collection),不同的是RCSP无法打破环状引用(cycles of references,比如:两个其实已经没被使用的对象彼此互指,因而好像还处在“被使用”状态)。
TR1的tr1::shared_ptr就是一个RCSP,所以函数f的又一版本来了:
void f()
{
std::tr1::shared_ptr pInv(createInvestment()); //在离开函数时,由shared_ptr析构函数自动删除pInv
...
}
这与auto_ptr版本基本一致,但shared_ptr的复制行为正常多了:
void f()
{
std::tr1::shared_ptr pInv1(createInvestment); //pInv1指向createInvestment返回物
std::tr1::shared_ptr pInv2(pInv1); //pInv2和pInv2指向同一个对象
pInv1 = pInv2; //同上,无任何改变
...
}
在函数f控制流结束时,pInv1和pInv2被销毁,其所指对象也就被自动销毁。由于tr1::shared_ptr的复制行为“一如预期”,它可被用于STL容器以及其它“auto_ptr之非正统复制行为并不适用”的语境上。
但是auto_ptr和tr1::shared_ptr两者都在其析构函数内做delete而不是delete[],这意味其不能用于动态分配的数组,而boost::scoped_array和boost::shared_array class则能提供这种行为。
二、资源管理类中小心coping行为
我们在使用C API函数处理类型为Mutex的互斥量对象(mutex object)时,一般会提供lock和unlock函数:
void lock(Mutex* pm); //锁定pm所指的互斥量
void unlokc(Mutex* pm); //将互斥量解除锁定
为了确保绝不会忘记将一个被锁住的Mutex解锁,一般会创建一个class来管理锁。这样的class的基本结构由RAII守则支配,也就是“资源在构造期间获得,在析构期间释放”:
class Lock {
public:
explicit Lock(Mutex* pm)
: mutexPtr(pm)
{ lock(mutexPtr); } //获得资源
~Lock() { unlock(mutexPtr); } //释放资源
private:
Mutex *mutexPtr;
};
客户对Lock的用户符合RAII方式:
Mutex m; //定义你需要的互斥量
...
{ //建立一个区块用来定义critical section
Lock ml(&m); //锁定互斥量
... //执行critical section内的操作
} //在区块最末尾,自动解除互斥量锁定
上面代码看似很完美,但是如果Lock对象被复制,又将如何呢?
Lock m11(&m); //锁定m
Lock m12(ml1); //将ml1复制到ml2身上,会发送什么呢?
一般为了防止复制RAII对象带来的副作用,会采取禁止复制的方式,也就是将coping操作声明为private,包括拷贝构造函数和赋值操作符。
三、承诺使用new和delete是要采取相同型式
成对使用new和delete时要采用相同型式,比如:如果你在new表达式中使用[],必须在相应的delete表达式中也使用[],否则的话其结果未定义(在delete时可能会导致太少的析构函数被调用);如果你在new表达式中不使用[],一定不要在相应的delete表达式中使用[]。
为什么会如此,因为在new单一对象和对象数组时内存布局会不同,可能的布局如下:
单一对象 object
对象数组 n | object |object | ...
其中,n表示数组大小,当然不同的编译器做法不尽相同。
四、独立语句将newed对象植入智能指针
假设我们有个函数用来揭示处理程序的优先权,另一个函数用来在某动态分配所得的widget上进行某些带优先权的处理:
int priority();
void processwidget(std::tr1::shared_ptr pw, int priority);
假设我们如此调用:
processwidget(std::tr1::shared_ptr(new widget), priority());
上面代码看似用对象管理资源,但是事实上确还是有可能泄露资源。因为编译器在产出一个processwidget调用码之前,会先核算即将被传递的各个实参,并做如下几件事情:
(1)调用函数priority
(2)执行new widget
(3)调用tr1::shared_ptr构造函数
但C++编译器不一定会按照上面顺序来生成代码,最终可能的操作序列会是:
(1)执行new widget
(2)调用priority函数
(3)调用tr1::shared_ptr构造函数
好吧,问题来了,如果在调用priority函数时产生异常,则new widget返回的指针会被遗失,因为其尚未被置入tr1::shared_ptr内,从而引发资源泄露。
避免产生这种问题的方法很简单:使用分离语句,分别写出(1)创建widget;(2)将它置入一个智能指针内,然后将智能指针传给processwidget函数:
std::tr1::shared_ptr pw(new widget);
processwidget(pw, priority());
以独立语句将newed对象存储于(置入)智能指针内,如果不这样做,一旦异常抛出,就有可能导致难以察觉的资源泄露。
相关推荐
C++人力资源管理系统源码 系统介绍 人力资源管理系统是这样的一种管理软件,它能够快速、方便地显示结果,还可以对有关工资的各种信息进行统计,服务于财务部门及公司主要管理者。实施人力资源管理系统可以集中、...
在本项目中,"C++模拟Windows资源管理器源码"是一个旨在实现类似Windows操作系统资源管理器功能的程序。这个程序允许用户浏览、操作文件和目录,如打开、复制、移动、删除等基本操作,同时也可能包括一些高级功能,...
C++ 使用孩子兄弟二叉树实现模拟资源管理器..................................................................................................................
随着现代先进的管理理念在组织中的发展,人力资源管理在组织管理中的作用也随即显得极其重要起来。我国组织先前大都是运用人事管理制度,与国际先进水平相比,这种人事管理效率总体水平比较落后,做好人事管理向人力资源...
3. **文件和目录操作**:高效资源管理器的核心功能之一是遍历和管理文件系统。这涉及到Windows API函数,如`FindFirstFile`、`FindNextFile`和`FindClose`,用于列举目录中的文件和子目录。 4. **多线程技术**:...
**C++编写的资源管理器**是一个初学者友好的项目,旨在模仿Windows操作系统中的资源管理器功能。这个项目是使用Microsoft Visual Studio 2003(一个早期版本的IDE)开发的,因此它基于较旧的C++标准,可能不包含现代...
在本文中,我们将深入探讨如何使用Visual C++来实现一个资源管理器。资源管理器是操作系统中的一个重要组件,它允许用户浏览、管理和操作文件及文件夹。在Visual C++环境中,我们可以利用MFC(Microsoft Foundation ...
在这个场景中,我们讨论的是使用C++编程语言,特别是微软的Visual C++(VC++)和Microsoft Foundation Classes(MFC)库来创建一个自定义的资源管理器。 C++是一种强大的、静态类型的、编译式的、通用的、面向对象...
在C++编程中,资源管理是一项至关重要的任务,因为它直接影响到程序的稳定性和效率。本文主要探讨了C++中的健壮指针和资源管理策略,旨在帮助开发者避免资源泄漏和提高程序的可靠性。 首先,资源是指程序运行过程中...
【标题】"客户资源管理系统C++"是一款使用C++编程语言开发的企业级应用程序,旨在有效管理和跟踪公司的客户信息。这个系统对于企业的销售、市场和服务部门至关重要,因为它可以帮助整合和分析客户数据,提升客户服务...
《C++实现的人力资源管理系统及其学习价值》 在信息技术高速发展的今天,人力资源管理系统的开发与应用已经成为企业管理的重要组成部分。本资源提供了一个基于C++编程语言实现的人力资源管理系统,对于初学者而言,...
本项目“C++编写的Windows资源管理器的资源树”旨在利用C++实现一个类似Windows资源管理器的功能,它是一个文件管理系统,能够以树状结构显示本地计算机上的文件和目录。 在Windows资源管理器中,用户通过资源树...
《C++实现的人力资源管理系统》 在信息技术领域,人力资源管理系统(HRMS)是一个至关重要的应用,它负责处理企业内部员工的信息、招聘、培训、考勤、薪酬福利等多个环节。本系统采用C++编程语言进行开发,这使得...
【C++信息资源管理系统】是一个基于C++编程语言和MFC(Microsoft Foundation Classes)框架的课程设计项目,旨在让学生在掌握C++面向对象编程的基础上,进一步学习和实践可视化编程技术。该系统主要用于职工信息的...
《客户资源管理系统C++源代码解析与探讨》 在信息技术高速发展的今天,客户资源管理系统(Customer Resource Management,CRM)已经成为企业提升效率、优化服务的重要工具。本文将详细解析一款基于C++编程语言实现...
本文将围绕一个基于C++、数据库技术和Microsoft Foundation Classes(MFC)的C++实例——客户资源管理系统进行深入探讨,旨在为开发者提供一套完整的开发思路和技术要点。 首先,C++作为一种强大的面向对象编程语言...
以上就是基于给定的标题和描述,对“企业人力资源管理系统(C++)”所涉及的C++编程知识的详细解析。通过这个项目,开发者不仅可以深化对C++的理解,还能学习到如何设计和实现一个实际的应用系统。
《C++人力资源管理系统详解》 在信息技术领域,C++是一种广泛应用的编程语言,以其高效、灵活和面向对象的特性深受开发者喜爱。本系统——“C++人力资源管理系统”就是基于C++语言开发的一款实用软件,旨在帮助企业...