C++资源管理应用技巧讲解

C++编程语言是一款功能强大的编程语言,它能够帮助开发人员轻松的实现各种功能。其中对于资源的管理是一个比较基础的知识,值得我们关注。在这里我们就为大家详细讲解C++资源管理的相关内容。#t#

我最喜欢的对资源的定义是:"任何在你的程序中获得并在此后释放的东西。"内存是一个相当明显的资源的例子。它需要用new来获得,用delete来释放。同时也有许多其它类型的资源文件句柄、重要的片断、Windows中的GDI资源,等等。 将资源的概念推广到程序中创建、释放的所有对象也是十分方便的,无论对象是在堆中分配的还是在栈中或者是在全局作用于内生命的。

对于给定的资源的拥有着,是负责释放资源的一个对象或者是一段代码。所有权分立为两种级别--自动的和显式的(automatic and explicit),如果一个对象的释放是由语言本身的机制来保证的,这个对象的就是被自动地所有。例如,一个嵌入在其他对象中的对象,他的清除需要其他对象来在清除的时候保证。外面的对象被看作嵌入类的所有者。 类似地,每个在栈上创建的对象(作为自动变量)的释放(破坏)是在控制流离开了对象被定义的作用域的时候保证的。这种情况下,作用于被看作是对象的所有者。注意所有的自动所有权都是和语言的其他机制相容的,包括异常。无论是如何退出作用域的--正常流程控制退出、一个break语句、一个return、一个goto、或者是一个throw--自动资源都可以被清除。

到目前为止,一切都很好!问题是在引入指针、句柄和抽象的时候产生的。如果通过一个指针访问一个对象的话,比如对象在堆中分配,C++不自动地关注它的释放。程序员必须明确的用适当的程序方法来释放这些资源。比如说,如果一个对象是通过调用new来创建的,它需要用delete来回收。一个文件是用CreateFile(Win32 API)打开的,它需要用CloseHandle来关闭。用EnterCritialSection进入的临界区(Critical Section)需要LeaveCriticalSection退出,等等。一个"裸"指针,文件句柄,或者临界区状态没有所有者来确保它们的最终释放。基本的资源管理的前提就是确保每个C++资源管理都有他们的所有者。

一个指针,一个句柄,一个临界区状态只有在我们将它们封装入对象的时候才会拥有所有者。这就是我们的第一规则:在构造函数中分配资源,在析构函数中释放资源。

当你按照规则将所有资源封装的时候,你可以保证你的程序中没有任何的资源泄露。这点在当封装对象(Encapsulating Object)在栈中建立或者嵌入在其他的对象中的时候非常明显。但是对那些动态申请的对象呢?不要急!任何动态申请的东西都被看作一种资源,并且要按照上面提到的方法进行封装。这一对象封装对象的链不得不在某个地方终止。它最终终止在最高级的所有者,自动的或者是静态的。这些分别是对离开作用域或者程序时释放资源的保证。

下面是C++资源管理的一个经典例子。在一个多线程的应用程序中,线程之间共享对象的问题是通过用这样一个对象联系临界区来解决的。每一个需要访问共享资源的客户需要获得临界区。例如,这可能是Win32下临界区的实现方法。

 

 
 
 
  1. class CritSect  
  2. {  
  3. friend class Lock;  
  4. public:  
  5. CritSect () { InitializeCriticalSection (&_critSection); }  
  6. ~CritSect () { DeleteCriticalSection (&_critSection); }  
  7. private  
  8. void Acquire ()  
  9. {  
  10. EnterCriticalSection (&_critSection);  
  11. }  
  12. void Release ()  
  13. {  
  14. LeaveCriticalSection (&_critSection);  
  15. }  
  16. CRITICAL_SECTION _critSection;  
  17. }; 

 

这里聪明的部分是我们确保每一个进入临界区的客户最后都可以离开。"进入"临界区的状态是一种资源,并应当被封装。封装器通常被称作一个锁(lock)。

 

 
 
 
  1. class Lock  
  2. {  
  3. public:  
  4. Lock (CritSect& critSect) : _critSect (critSect)  
  5. {  
  6. _critSect.Acquire ();  
  7. }  
  8. ~Lock ()  
  9. {  
  10. _critSect.Release ();  
  11. }  
  12. private  
  13. CritSect & _critSect;  
  14. }; 

 

锁一般的用法如下:

 

 
 
 
  1. void Shared::Act () throw (char *)  
  2. {  
  3. Lock lock (_critSect);  
  4. // perform action -- may throw  
  5. // automatic destructor of lock  

 

注意无论发生什么,临界区都会借助于语言的机制保证释放。

还有一件需要记住的事情--每一种C++资源管理都需要被分别封装。这是因为资源分配是一个非常容易出错的操作,是要资源是有限提供的。我们会假设一个失败的资源分配会导致一个异常--事实上,这会经常的发生。所以如果你想试图用一个石头打两只鸟的话,或者在一个构造函数中申请两种形式的资源,你可能就会陷入麻烦。只要想想在一种资源分配成功但另一种失败抛出异常时会发生什么。因为构造函数还没有全部完成,析构函数不可能被调用,第一种资源就会发生泄露。

这种情况可以非常简单的避免。无论何时你有一个需要两种以上资源的类时,写两个笑的封装器将它们嵌入你的类中。每一个嵌入的构造都可以保证删除,即使包装类没有构造完成。

免责声明:文章内容不代表本站立场,仅供读者参考。产品相关技术问题请发送工单。 本文链接:https://www.idc.net/help/402720/

为您推荐

开源数据收集引擎 Logstash 讲解和示例讲解

一、概述 Logstash 是一个开源的数据收集和日志处理工具,它是 Elastic Stack(ELK Stack)的一部分,用于从各种数据源中采集、转换和传输数据,以帮助分析和可视化大规模数据。Logstash 通常与 Elasticsearch 和 Ki...

八个开源免费单点登录(SSO)系统

单点登录(SSO)是一个登录服务层,通过一次登录访问多个应用。使用SSO服务可以提高多系统使用的用户体验和安全性,用户不必记忆多个密码、不必多次登录浪费时间。 下面推荐一些市场上最好的开源SSO系统,可作为商业SSO替代。 1.Authelia https://github.com/authelia/authelia ...

浅谈HBase数据结构和系统架构

Part 01 LSM树模型 常见的的关系型数据库,如MySQL、SQL Server、Oracle等,使用B+ Tree作为数据存储与索引的基本结构,非叶子节点只存放索引数据,叶子节点存放所有数据和指向相邻节点的指针,具有高效的范围查询和稳定的查找效率,以及具有较小的读放大和空间放大。采用磁盘随机读写方式,且以磁盘数...

微软Radius平台重构现代应用程序部署

微软的 Azure 孵化团队日前推出一个叫 Radius 的新应用平台。Radius 平台可用于在 Kubernetes、公共云和边缘环境中运行各种现代应用程序。 Radius 是一个开源项目,最初支持的应用程序运行时包括Kubernetes、Azure和AWS,以后还会支持诸如谷歌云平台等云环境。 Mark Russ...

Ext JS3.0正式版发布

Ext JS3.0在经历数次RC版之后,extjs.com终于发布3.0的正式版。总体而言,较2.0改进不大,依然还是原理的组件模型,具体更新及改进如下: ◆提供了参照DWR后与后台的通讯包Direct,支持具有明显的REST风格的CRUD服务 ◆一系列的新的组件和例子,包括有图表(Charting, By YUI F...
返回顶部