`
网络接口
  • 浏览: 44892 次
文章分类
社区版块
存档分类
最新评论

C++之资源管理

 
阅读更多

所谓资源就是一旦使用完,就必须将其归还给系统,否则就有你好果子吃。在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++人力资源管理系统源码 系统介绍 人力资源管理系统是这样的一种管理软件,它能够快速、方便地显示结果,还可以对有关工资的各种信息进行统计,服务于财务部门及公司主要管理者。实施人力资源管理系统可以集中、...

    C++模拟windows资源管理器源码

    在本项目中,"C++模拟Windows资源管理器源码"是一个旨在实现类似Windows操作系统资源管理器功能的程序。这个程序允许用户浏览、操作文件和目录,如打开、复制、移动、删除等基本操作,同时也可能包括一些高级功能,...

    C++ 模拟资源管理器

    C++ 使用孩子兄弟二叉树实现模拟资源管理器..................................................................................................................

    基于C++人事资源管理系统

    随着现代先进的管理理念在组织中的发展,人力资源管理在组织管理中的作用也随即显得极其重要起来。我国组织先前大都是运用人事管理制度,与国际先进水平相比,这种人事管理效率总体水平比较落后,做好人事管理向人力资源...

    c++ MFC 高效资源管理器

    3. **文件和目录操作**:高效资源管理器的核心功能之一是遍历和管理文件系统。这涉及到Windows API函数,如`FindFirstFile`、`FindNextFile`和`FindClose`,用于列举目录中的文件和子目录。 4. **多线程技术**:...

    C++编写的资源管理器

    **C++编写的资源管理器**是一个初学者友好的项目,旨在模仿Windows操作系统中的资源管理器功能。这个项目是使用Microsoft Visual Studio 2003(一个早期版本的IDE)开发的,因此它基于较旧的C++标准,可能不包含现代...

    资源管理器 Visual C++实现源码

    在本文中,我们将深入探讨如何使用Visual C++来实现一个资源管理器。资源管理器是操作系统中的一个重要组件,它允许用户浏览、管理和操作文件及文件夹。在Visual C++环境中,我们可以利用MFC(Microsoft Foundation ...

    用C++编写的资源管理器

    在这个场景中,我们讨论的是使用C++编程语言,特别是微软的Visual C++(VC++)和Microsoft Foundation Classes(MFC)库来创建一个自定义的资源管理器。 C++是一种强大的、静态类型的、编译式的、通用的、面向对象...

    C++中的健壮指针和资源管理

    在C++编程中,资源管理是一项至关重要的任务,因为它直接影响到程序的稳定性和效率。本文主要探讨了C++中的健壮指针和资源管理策略,旨在帮助开发者避免资源泄漏和提高程序的可靠性。 首先,资源是指程序运行过程中...

    客户资源管理系统C++

    【标题】"客户资源管理系统C++"是一款使用C++编程语言开发的企业级应用程序,旨在有效管理和跟踪公司的客户信息。这个系统对于企业的销售、市场和服务部门至关重要,因为它可以帮助整合和分析客户数据,提升客户服务...

    用 C++编的 人力资源管理系统 有源代码和系统界面

    《C++实现的人力资源管理系统及其学习价值》 在信息技术高速发展的今天,人力资源管理系统的开发与应用已经成为企业管理的重要组成部分。本资源提供了一个基于C++编程语言实现的人力资源管理系统,对于初学者而言,...

    C++编写的Windows资源管理器的资源树

    本项目“C++编写的Windows资源管理器的资源树”旨在利用C++实现一个类似Windows资源管理器的功能,它是一个文件管理系统,能够以树状结构显示本地计算机上的文件和目录。 在Windows资源管理器中,用户通过资源树...

    人力资源管理系统,C++编写

    《C++实现的人力资源管理系统》 在信息技术领域,人力资源管理系统(HRMS)是一个至关重要的应用,它负责处理企业内部员工的信息、招聘、培训、考勤、薪酬福利等多个环节。本系统采用C++编程语言进行开发,这使得...

    C++信息资源管理系统

    【C++信息资源管理系统】是一个基于C++编程语言和MFC(Microsoft Foundation Classes)框架的课程设计项目,旨在让学生在掌握C++面向对象编程的基础上,进一步学习和实践可视化编程技术。该系统主要用于职工信息的...

    客户资源管理系统C++源代码

    《客户资源管理系统C++源代码解析与探讨》 在信息技术高速发展的今天,客户资源管理系统(Customer Resource Management,CRM)已经成为企业提升效率、优化服务的重要工具。本文将详细解析一款基于C++编程语言实现...

    客户资源管理系统.C++ 数据库 MFC C++实例 管理系统

    本文将围绕一个基于C++、数据库技术和Microsoft Foundation Classes(MFC)的C++实例——客户资源管理系统进行深入探讨,旨在为开发者提供一套完整的开发思路和技术要点。 首先,C++作为一种强大的面向对象编程语言...

    企业人力资源管理系统(C++)

    以上就是基于给定的标题和描述,对“企业人力资源管理系统(C++)”所涉及的C++编程知识的详细解析。通过这个项目,开发者不仅可以深化对C++的理解,还能学习到如何设计和实现一个实际的应用系统。

    c++人力资源管理系统带使用录像.zip

    《C++人力资源管理系统详解》 在信息技术领域,C++是一种广泛应用的编程语言,以其高效、灵活和面向对象的特性深受开发者喜爱。本系统——“C++人力资源管理系统”就是基于C++语言开发的一款实用软件,旨在帮助企业...

Global site tag (gtag.js) - Google Analytics