Effective C++: 03资源管理
所谓资源,就是一旦用了它,将来必须还给系统。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());
Effective C++: 03资源管理的更多相关文章
- 《Effective C++》资源管理:条款13-条款17
条款13:以对象管理资源 为了防止资源泄漏,请使用RAII(Resource Acquisition Is Initialization)对象,在构造函数里面获得资源,在析构函数里面释放资源 auto ...
- 【Effective C++】资源管理
资源:动态分配的内存.文件描述器.互斥锁.图形界面中的字型与笔刷.数据库连接以及网络sockets等,无论哪一种资源,重要的是,当你不再使用它时,必须将它还给系统. 条款13:以对象管理资源 当我们向 ...
- Effective Java 03 Enforce the singleton property with a private constructor or an enum type
Principle When implement the singleton pattern please decorate the INSTANCE field with "static ...
- Effective C++ 3.资源管理
//条款13:以对象管理资源 // 1.C++程序中最常使用的资源就是动态分配内存,并且还包括文件描述器,互斥锁,GDI对象.数据库连接.网络socket等.不管哪一种资源,当不再使用的时候必须将其归 ...
- effective c++:资源管理
对象管理资源 createInvestment 函数作用时创建一个invest对象: void f() { Investment *pInv = createInvestment(); // call ...
- const 修饰成员函数 前后用法(effective c++ 03)
目录 const在函数后面 const修饰成员函数的两个作用 const在函数前面 总结 const在函数后面 类的成员函数后面加 const,表明这个函数不会对这个类对象的数据成员(准确地说是非静态 ...
- More Effective C++: 03异常
C++的异常机制使得程序付出某些代价:资源泄漏的可能性增加了:写出具有你希望的行为的构造函数与析构函数变得更加困难:执行程序和库程序尺寸增加了,同时运行速度降低了等等. 但是为什么使用异常呢?C程序使 ...
- Effective Java Index
Hi guys, I am happy to tell you that I am moving to the open source world. And Java is the 1st langu ...
- Effective C++笔记03:资源管理
资源:动态分配的内存.文件描写叙述器.相互排斥锁.图形界面中的字型与笔刷.数据库连接以及网络sockets等,不管哪一种资源,重要的是,当你不再使用它时,必须将它还给系统. 条款13:以对象管理资源 ...
随机推荐
- WebConfig配置文件
<?xml version="1.0"?> <!--注意: 除了手动编辑此文件以外,您还可以使用 Web 管理工具来配置应用程序的设置.可以使用 Visual S ...
- Centos Apache 多站点配置
首先明白APACHE配置文件位置 /etc/httpd/ 系统会自动加载 "/etc/httpd/conf.d" 目录下面的 "*.conf"文件 创建多个 & ...
- PHP--http_build_query--把数组化成&key=value方式
- Linux中管理员用户与普通用户之间的切换
使用su进行用户切换 管理员用户切换至普通用户: su [用户名] 使用su命令从高级别用户切换至低级别用户无需输入密码 普通用户切换至管理员用户: 普通用户切换至管理员用户使用 su - 使用l ...
- SOFARPC学习(一)
接触SOFARPC,是从一个好朋友(女程序媛)的推荐开始,目的是从头到尾了解这个框架,包括使用方法和源码解析. 当学习一个新东西的事物,我总喜欢先总体把握,在深入细节,这样就可以有种高屋建瓴的感觉,否 ...
- Oil Deposits HDU - 1241 (dfs)
Oil Deposits HDU - 1241 The GeoSurvComp geologic survey company is responsible for detecting undergr ...
- CSS 定位 (Positioning)
CSS 定位 (Positioning) 属性允许你对元素进行定位. CSS 定位和浮动 CSS 为定位和浮动提供了一些属性,利用这些属性,可以建立列式布局,将布局的一部分与另一部分重叠,还可以完成多 ...
- 基于python爬虫的github-exploitdb漏洞库监控与下载
基于python爬虫的github-exploitdb漏洞库监控与下载 offensive.py(爬取项目历史更新内容) #!/usr/bin/env python # -*- coding:utf- ...
- Socket与TcpClient的区别
原文:Socket与TcpClient的区别 Socket和TcpClient有什么区别 原文:http://wxwinter.spaces.live.com/blog/cns!C36588978AF ...
- day37 04-Hibernate二级缓存:list和iterate方法比较
get()和load()方法既可以向一级缓存区放数据,也可以向二级缓存区放数据.这是查询一个的情况.要是查询所有呢?注意, // 查询所有.Query接口的list()方法. // list()方法会 ...