Effective C++ 改善程序与设计的55个具体做法 二周目笔记03
2015-09-17 15:13
351 查看
第三部分 资源管理
条款13:以对象管理资源
如果在delete之前,程序return或者continue到其他位置或者抛出异常,总之无论delete如何被忽略过去,泄露的不只是内存还有其中保存的一些重要数据。许多资源被动态分配于heap内然后被用于单一区块或函数内。它们应该在控制流离开那个区块或函数时被释放。标准程序库中auto_ptr正是针对这种形势而设计的特制产品。
获得资源后立刻放进管理对象内。实际上“以对象管理资源”的观念常被称为“资源取得时机便是初始化时机”(resource acquisition
is initialization;RAII)
管理对象(manageing object)运用析构函数确保资源被释放。
由于资源管理对象被销毁时会自动删除它们所管理的(内容)内存。如果多个auto_ptr同时指向同一对象。对象会被删除一次以上,程序报错或者产生未定义行为。为了预防这个问题,auto_ptr通过copy构造函数copy
assignment 操作符在复制它们的时候会变成null,而复制的指针的将取得资源的唯一所有权。
Auto_ptr的替代方案是“引用计数型智慧 指针(reference-countingsmart pointer;RCSP)”。所谓RCSP是指,持续追踪共有多少对象指针指向某笔资源,并在无人指向它的时候自动删除该资源。
由于STL要求容器内部元素可以正常复制,所以STL容器总不可以存储auto_ptr,亦即类似vector<auto_ptr<int>>some_vector;是禁止的。
RCSP无法逃离的梦靥:环状引用。
Auto_ptr和tr1::shared_ptr两者都在其析构函数内实现delete而不是delete[]动作。那么此时,
#include <memory>
std::auto_ptr<int> api(new int[10]);
std::shared_ptr<std::string> sps(new std::string[10]);
销毁api和sps之时便会产生未定义行为。
条款14:在资源管理类中小心copying行为
在设计copying行为时,根据需要有四种选项:
禁止复制;
使用引用计数;
深拷贝;
转移所有权。
另外,shared_ptr允许制定所谓的“删除器“(deleter),那是一个函数或者函数对象,当引用次数为0时,便被调用(此机能并不存在于auto_ptr——它总是将其指针删除)。
条款15:在资源管理类中提供对原始资源的访问
APIs往往要求访问原始资源(raw resource),所以每一个RAII
class应该提供一个“取得其所管理只资源“的办法。对于原始资源的访问可能经由显式转换或隐式转换。一般而言,显式转换比较安全,但隐式转换对客户比较方便。两种转换实现一种即可,例如下:
class raw_resources_base_class {};
//根据不同的参数产生不容的原始资源,这里为了方便演示,省略参数
raw_resources_base_class* create_resource(){};
class resources_mangaging_class
{
resources_mangaging_class(raw_resources_base_class * p) :Praw_reasource(p){}
operator raw_resources_base_class *() const { return Praw_reasource; }//隐式转换
raw_resources_base_class * get() const { return Praw_reasource; }//显式转换
~resources_mangaging_class(){ delete Praw_reasource; }
private:
raw_resources_base_class *Praw_reasource;
};
条款16:成对使用new和delete时要采取相同的形式
即将被删除的的那个指针,所指的是单一对象还是对象数组?这是个比不可却的问题,因为单一对象的内存布局一般而言不同于数组的内存布局。更明确地说,数组所用的内存通常还包括“数组大小“的记录,以便delete知道需要调用多少次析构函数。单一对象的内存则没有这笔记录。你可以把两种不同的内存布局想象如下,其中n是数组大小:
虽然很多编译器都是这么实现的,但是编译器并不需非得这么实现不可,这只是一个例子。
无论是对new使用delete[ ]还是对new[]使用delete,所引发的结果都是未定义的。所以,成对使用new和delete时要采取相同的形式。
条款17:以独立的语句将newed对象置入智能指针
int priority();
void process_something(std::shared_ptr<int> one, int priority);
process_something(std::shared_ptr<int>(new int), priority());
//编译器产生process_something调用码之前,必须核算即将被传递的各个实参。
//于是在调用process_something之前,必须创建代码,做一下三件事情:
//调用priority()
//执行“new int”
//调用share_ptr构造函数
编译器选择什么样的顺序完成这些事情的弹性很大。如果是以下次序(说不定会产生更高效的代码):
执行“new int”;
调用priority();
调用share_ptr构造函数。
如果,priority()调用导致异常,在此情况下,“new int“返回的指针将会遗失,造成资源泄露。由于编译器对于”跨越语句的各项操作“没有重新排列的自由(只有在语句内它才拥有那个自由度)。因此可做一下调用的修改:
std::shared_ptr<int> Pi(new int);
process_something(Pi, priority());
条款13:以对象管理资源
如果在delete之前,程序return或者continue到其他位置或者抛出异常,总之无论delete如何被忽略过去,泄露的不只是内存还有其中保存的一些重要数据。许多资源被动态分配于heap内然后被用于单一区块或函数内。它们应该在控制流离开那个区块或函数时被释放。标准程序库中auto_ptr正是针对这种形势而设计的特制产品。
获得资源后立刻放进管理对象内。实际上“以对象管理资源”的观念常被称为“资源取得时机便是初始化时机”(resource acquisition
is initialization;RAII)
管理对象(manageing object)运用析构函数确保资源被释放。
由于资源管理对象被销毁时会自动删除它们所管理的(内容)内存。如果多个auto_ptr同时指向同一对象。对象会被删除一次以上,程序报错或者产生未定义行为。为了预防这个问题,auto_ptr通过copy构造函数copy
assignment 操作符在复制它们的时候会变成null,而复制的指针的将取得资源的唯一所有权。
Auto_ptr的替代方案是“引用计数型智慧 指针(reference-countingsmart pointer;RCSP)”。所谓RCSP是指,持续追踪共有多少对象指针指向某笔资源,并在无人指向它的时候自动删除该资源。
由于STL要求容器内部元素可以正常复制,所以STL容器总不可以存储auto_ptr,亦即类似vector<auto_ptr<int>>some_vector;是禁止的。
RCSP无法逃离的梦靥:环状引用。
Auto_ptr和tr1::shared_ptr两者都在其析构函数内实现delete而不是delete[]动作。那么此时,
#include <memory>
std::auto_ptr<int> api(new int[10]);
std::shared_ptr<std::string> sps(new std::string[10]);
销毁api和sps之时便会产生未定义行为。
条款14:在资源管理类中小心copying行为
在设计copying行为时,根据需要有四种选项:
禁止复制;
使用引用计数;
深拷贝;
转移所有权。
另外,shared_ptr允许制定所谓的“删除器“(deleter),那是一个函数或者函数对象,当引用次数为0时,便被调用(此机能并不存在于auto_ptr——它总是将其指针删除)。
条款15:在资源管理类中提供对原始资源的访问
APIs往往要求访问原始资源(raw resource),所以每一个RAII
class应该提供一个“取得其所管理只资源“的办法。对于原始资源的访问可能经由显式转换或隐式转换。一般而言,显式转换比较安全,但隐式转换对客户比较方便。两种转换实现一种即可,例如下:
class raw_resources_base_class {};
//根据不同的参数产生不容的原始资源,这里为了方便演示,省略参数
raw_resources_base_class* create_resource(){};
class resources_mangaging_class
{
resources_mangaging_class(raw_resources_base_class * p) :Praw_reasource(p){}
operator raw_resources_base_class *() const { return Praw_reasource; }//隐式转换
raw_resources_base_class * get() const { return Praw_reasource; }//显式转换
~resources_mangaging_class(){ delete Praw_reasource; }
private:
raw_resources_base_class *Praw_reasource;
};
条款16:成对使用new和delete时要采取相同的形式
即将被删除的的那个指针,所指的是单一对象还是对象数组?这是个比不可却的问题,因为单一对象的内存布局一般而言不同于数组的内存布局。更明确地说,数组所用的内存通常还包括“数组大小“的记录,以便delete知道需要调用多少次析构函数。单一对象的内存则没有这笔记录。你可以把两种不同的内存布局想象如下,其中n是数组大小:
虽然很多编译器都是这么实现的,但是编译器并不需非得这么实现不可,这只是一个例子。
无论是对new使用delete[ ]还是对new[]使用delete,所引发的结果都是未定义的。所以,成对使用new和delete时要采取相同的形式。
条款17:以独立的语句将newed对象置入智能指针
int priority();
void process_something(std::shared_ptr<int> one, int priority);
process_something(std::shared_ptr<int>(new int), priority());
//编译器产生process_something调用码之前,必须核算即将被传递的各个实参。
//于是在调用process_something之前,必须创建代码,做一下三件事情:
//调用priority()
//执行“new int”
//调用share_ptr构造函数
编译器选择什么样的顺序完成这些事情的弹性很大。如果是以下次序(说不定会产生更高效的代码):
执行“new int”;
调用priority();
调用share_ptr构造函数。
如果,priority()调用导致异常,在此情况下,“new int“返回的指针将会遗失,造成资源泄露。由于编译器对于”跨越语句的各项操作“没有重新排列的自由(只有在语句内它才拥有那个自由度)。因此可做一下调用的修改:
std::shared_ptr<int> Pi(new int);
process_something(Pi, priority());
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- C++ Custom Control控件向父窗体发送对应的消息
- C++中拷贝构造函数的应用详解