C++内存管理学习笔记(4)

/****************************************************************/

/*            学习是合作和分享式的!

/* Author:Atlas                    Email:wdzxl198@163.com   

/*  转载请注明本文出处:

*   http://blog.csdn.net/wdzxl198/article/details/9094793

/****************************************************************/

上期内容回顾:传送门1传送门2传送门3

1.C++内存管理

1.1c语言和C++内存分配

1.2区分堆、栈、静态存储区

1.3控制C++的内存分配

1.4内存管理的基本要求

1.5常见的内存错误及对策

1.6数组和指针
1.7指针参数是如何传递内存的
1.8杜绝“野指针“
1.9malloc、free和new、delete的区别
1.10-1.12 malloc,free,new,delete使用

2.C++中的健壮指针及资源管理

      对于资源,就是一旦用了它,将来必须还给系统。我们最常见的资源是动态分配内存,其他常见的还有:文件描述器、互斥锁、图形界面中的字形和笔刷、数据库连接、以及网络socket等等。

2.1 引入      

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

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

2.2 第一条规则RAII(Resource Acquisition IInitialization)

       RAII是指C++语言中的一个惯用法(idiom),它是“Resource Acquisition IInitialization”的首字母缩写。中文可将其翻译为“资源获取就是初始化”。我们怎么理解这句话呢,在一本c++书中有这么一句:“使用局部对象管理资源的技术通常称为“资源获取就是初始化(RAII)”。这种通用技术依赖于构造函数和析构函数的性质以及它们与异常处理的交互作用。”通俗的说一下就是:一个指针,一个句柄,一个临界区状态只有在我们将它们封装入对象的时候才会拥有所有者。这就是我们的第一规则:在构造函数中分配资源,在析构函数中释放资源。

     为什么会有这个规则?为什么资源要在构造函数中申请及初始化以及析构函数中释放?让我们一个例子来说明,

下面的UseFile函数中:

   1: void UseFile(char const* fn)
   2: {
   
   3:     FILE* f = fopen(fn, "r"); // 获取资源
   4:     // 在此处使用文件句柄f...    // 使用资源
   5:     fclose(f); // 释放资源
   6: }

      调用fopen()打开文件就是获取文件句柄资源,操作完成之后,调用fclose()关闭文件就是释放该资源。资源的释放工作至关重要,如果只获取而不释放,那么资源最终会被耗尽。上面的代码是否能够保证在任何情况下都调用fclose函数呢?请考虑如下情况:

   1: void UseFile(char const* fn)
   2: {
   
   3:     FILE* f = fopen(fn, "r"); // 获取资源
   4:     // 使用资源
   5:     if (!g()) return; // 如果操作g失败!
   6:     // ...
   7:     if (!h()) return; // 如果操作h失败!
   8:     // ...
   9:     fclose(f); // 释放资源
  10: }

     在使用文件f的过程中,因某些操作失败而造成函数提前返回的现象经常出现。在操作g或h失败之后,UseFile函数必须首先调用fclose()关闭文件,然后才能返回其调用者,否则会造成资源泄漏。因此,需要将UseFile函数修改为:

   1:     void UseFile(char const* fn)
   2:     {
   
   3:     FILE* f = fopen(fn, "r"); 
   4:     //获取资源
   5:     //使用资源
   6:     if (!g()) 
   7:     {fclose(f);return; }
   8:     // ...
   9:     if (!h()) 
  10:     {fclose(f);return; }
  11:     // ...
  12:     fclose(f); 
  13:     //释放资源
  14: }

      现在的问题是:用于释放资源的代码fclose(f)需要在不同的位置重复书写多次。如果再加入异常处理,情况会变得更加复杂。

      假设UseResources函数要用到n个资源,则进行资源管理的一般模式为:

   1: void UseResources()
   2: {
   
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值