所谓资源,就是一旦用了它,将来必须还给系统。C++中的资源有:内存、文件描述符、互斥锁、数据库连接、网络socket等。

13:以对象管理资源

1:像下面这个函数:

void f()
{
Investment *pInv = createInvestment();
...
delete pInv;
}

这个函数中,会有若干情况的发生导致无法执行delete语句,比如”...”内可能有一个过早的return语句;或者createInvestment和delete位于某个循环内,而该循环由于某个continue或goto语句过早退出;或者”...”内的语句抛出了异常。

2:为确保createInvestment返回的资源总是被释放,我们需要将资源放进对象内,当控制流离开f,该对象的析构函数会自动释放那些资源。

把资源放进对象内,我们便可倚赖C++的“析构函数自动调用机制”确保资源被释放。比如使用auto_ptr智能指针(auto_ptr已过时,这里仅拿它举例而已):

void f()
{
std::auto_ptr<Investment> pInv(createInvestment());
...
}

3:new以对象管理资源,有两个关键点:

A:获得资源后立即放进管理对象:“以对象管理资源”的观念常被称为“资源取得时机便是初始化时机”(Resource Acquisition Is Initialization,  RAII),因为我们几乎总是在获得一笔资源后于同一语句内以它初始化某个管理对象。有时候获得的资源被拿来赋值某个管理对象,但不论哪一种做法,每一笔资源都在获得的同时立刻被放进管理对象中。

B:管理对象运用析构函数确保资源被释放:不论控制流如何离开区块,一旦对象被销毁,其析构函数自然会被自动调

4:如果你打算手工释放资源,容易发生某些错误。罐装式的资源管理类如std::shared_ptr往往比较能够轻松遵循本条款忠告,但有时候你所使用的资源是目前这些预制式classes无法妥善管理的。既然如此就需要精巧制作你自己的资源管理类。

14:在资源管理类中小心copying行为

每一位RAII class作者一定会面对这样一个问题:“当一个RAII对象被复制,会发生什么事?”大多数时候你会选择以下几种可能:

1:禁止复制;

2:对底层资源使用引用计数法,就像std::shared_ptr那样。通常只要内涵一个std::shared_ptr成员变量,RAII classes便可实现出reference-counting copying行为;

3:复制底层资源;

4:转移底层资源的拥有权,就像std::auto_ptr那样;

15:在资源管理类中提供对原始资源的访问

有时候需要一个函数可将RAII class对象转换为其所含的原始数据,比如std::shared_ptr中的get成员函数,用来执行显示转换,也就是它会返回智能指针内部的原始指针;而且std::shared_ptr也重载了operaotr*和operator->函数,允许隐式转换至底部原始指针。

有些RAII class的作者会提供一个隐式转换函数,用于将RAII对象转换为原始资源,这通常不是一个好的做法。

16:成对使用new和delete时要采取相同形式

1:数组所用的内存通常还包括“数组大小”的记录,以便delete知道需要调用多少次析构函数。单一对象的内存则没有这笔记录。可以把两种不同的内存布局想象如下,其中n是数组大小:

因此:如果你调用new时使用[],你必须在对应调用delete时也使用[]。如果你调用new时没有使用[],那么也不该在对应调用delete时使用[]。违反上面的规则化,将会引起未定义行为。

要注意typedef数组的情况:

typedef std::string AddressLines[];
std::string *pal = new AddressLines;

上面的AddressLines是个数组,尽管这里表面上使用new,实际上是用了new[],所以,delete时需要delete[]:

delete pal;        // 未定义
delete [] pal; // fine

为了避免上面的错误,最好尽量不要对数组形式做typedef。

17:以独立语句将new对象置入智能指针

像下面这样的函数调用,也有可能泄漏资源:

processWidget(std::shared_ptr<Widget>(new Widget), priority()); 

原因在于:在调用processWidget之前,编译器必须创建代码,做以下三件事:调用priority;执行”new Widget”;调用std::shared_pt构造函数。

C++没有规定编译器必须以怎样的次序完成这三件事,有可能是以下面的次序:执行”new Widget”;调用priority;调用std::shared_pt构造函数。

这种情况下,万一对priority的调用导致异常,此时”new Widget”返回的指针将会丢失,从而造成资源泄漏。这种情况的发生是因为:在“资源被创建”和“资源被转换为资源管理对象”两个时间点之间有可能发生异常。

为了避免这种情况的发生,使用分离语句:

std::shared_ptr<Widget> pw(new Widget); 

processWidget(pw, priority());   

最新文章

  1. iOS 多线程GCD的基本使用
  2. hashCode与equals的区别与联系
  3. 51nod1049(计算最大子段和)
  4. C#之参数线程
  5. Effective C++ 条款45
  6. Pair Project: Elevator Scheduler [电梯调度算法的实现和测试]:思考题——谢勤政11061197
  7. [转] boost库的Singleton的实现以及static成员的初始化问题
  8. php-timeit估计php函数的执行时间
  9. Tiny6410之控制icache驱动
  10. V8引擎嵌入指南
  11. devexpress实现单元格合并以及依据条件合并单元格
  12. Python进阶8---面向对象基础1
  13. synchronized 与 volatile 原理 —— 内存屏障的重要实践
  14. 深挖JDK动态代理(一)
  15. assetBundle 中的prefeb资源图片显示粉色方框
  16. (转)mtr命令详解诊断网络路由
  17. 没有内涵段子可以刷了,利用Python爬取段友之家贴吧图片和小视频(含源码)
  18. Python3练习题系列(08)——代码阅读方法及字典跳转表理解
  19. eclipse查看方法被那些代码调用open call hierarchy
  20. 从无到有,用Nodejs+express+mongodb搭建简易登陆系统

热门文章

  1. idea创建管理项目
  2. LA3902 Networlk
  3. LeetCode412Fizz Buzz
  4. nslookup获取域名对应的的ip地址
  5. 【python之路36】进程、线程、协程相关
  6. 前端js错误日志收集
  7. java-String-StringBuffer
  8. day36 11-Hibernate中的事务:当前线程中的session
  9. 洛谷P1352 没有上司的舞会 [2017年5月计划 清北学堂51精英班Day3]
  10. 统计Linux下的CPU状态信息