使用RAII技术来管理资源
2017-05-20 21:55
309 查看
http://blog.csdn.net/holmeswu/article/details/38436825
我们考虑以下的代码:
[cpp]
view plain
copy
print?
void func(){
Book* ptr = new Book();
......
delete ptr; //一定会执行到这里吗?
}
这是很常见的代码,它看起来或许妥当,但是在若干情况下我们无法释放ptr所指向的对象。或许开发人员在“......”区域添加了一个过早的return语句,如果这样一个return被执行起来,那么控制流就一定不会触碰delete语句。亦或是“......”区域内的语句抛出异常,果真如此的话delete语句还是不会被执行。总而言之,这样的代码不安全。而要解决这样的问题,我们需要RAII技术。
C++中RAII的全称是“Resource acquisition is initialization”,直译为“资源获取即初始化”。RAII的核心思想是将资源和对象的生命周期捆绑起来,对象创建获取资源,对象销毁释放资源。简单来说就是使用对象来管理资源,也就是创建一个对象并将资源的生命周期和对象的生命周期相关联,如此一来就可以用对象的管理设施来管理资源。最简单的RAII形式是,创建这样一个对象:其构造函数获取这份资源,析构函数释放这份资源。
[cpp]
view plain
copy
print?
class Book{......};
class BookHandle{
public:
Explicit BookHandle(Book* bk): book(bk){}
~BookHandle(){delete book;}
Book* get(){return book;}
private:
BookHandle(const Book&);
BookHandle& operator=(const Book&);
Book* book;
};
BookHandle的好处在于我们可以不用理会控制流如何离开区块,一旦对象被销毁(离开作用区域),其析构函数自然会被调用,于是资源被释放。如果资源释放可能会抛出异常,这或许有些麻烦,但是前面我们已经讨论过此问题,便不用担心了。因此上面的代码会发生以下的变化:
[cpp]
view plain
copy
print?
void func(){
BookHandle bh(new Book());
...... //不用担心控制流如何离开
//bh的析构函数释放资源
}
但是也有一种情况使得RAII也变得不安全,那就是将RAII对象分配到堆上时。这时只有显示的使用delete来删除BookHandle对象才能让BookHandle对象的析构函数来释放其所包含的对象。
[cpp]
view plain
copy
print?
BookHandle* bh = new BookHandle(new Book()); //糟糕的主意
两个常用的RAII classes的对象是shared_ptr和auto_pt,前者通常是较好的选择。但是并非所有的资源都是heap-based,对于那种资源来说,像auto_ptr和shared_ptr往往不适合作为资源掌握者。既然如此,你可能需要建立自己的RAII calsses。对此还要注意它的copying的行为。一般而言,我们不允许对RAII class进行copy。但是事无绝对,如果你非要如此的话,请记住要对其进行深度拷贝。还要注意,每一个RAII class都应该提供一个“取得其所管理之资源”的办法。对原始资源的访问可能经由显示转换或隐式转换。显示转换比较安全,但隐式转换对客户比较方便。
我们考虑以下的代码:
[cpp]
view plain
copy
print?
void func(){
Book* ptr = new Book();
......
delete ptr; //一定会执行到这里吗?
}
这是很常见的代码,它看起来或许妥当,但是在若干情况下我们无法释放ptr所指向的对象。或许开发人员在“......”区域添加了一个过早的return语句,如果这样一个return被执行起来,那么控制流就一定不会触碰delete语句。亦或是“......”区域内的语句抛出异常,果真如此的话delete语句还是不会被执行。总而言之,这样的代码不安全。而要解决这样的问题,我们需要RAII技术。
C++中RAII的全称是“Resource acquisition is initialization”,直译为“资源获取即初始化”。RAII的核心思想是将资源和对象的生命周期捆绑起来,对象创建获取资源,对象销毁释放资源。简单来说就是使用对象来管理资源,也就是创建一个对象并将资源的生命周期和对象的生命周期相关联,如此一来就可以用对象的管理设施来管理资源。最简单的RAII形式是,创建这样一个对象:其构造函数获取这份资源,析构函数释放这份资源。
[cpp]
view plain
copy
print?
class Book{......};
class BookHandle{
public:
Explicit BookHandle(Book* bk): book(bk){}
~BookHandle(){delete book;}
Book* get(){return book;}
private:
BookHandle(const Book&);
BookHandle& operator=(const Book&);
Book* book;
};
BookHandle的好处在于我们可以不用理会控制流如何离开区块,一旦对象被销毁(离开作用区域),其析构函数自然会被调用,于是资源被释放。如果资源释放可能会抛出异常,这或许有些麻烦,但是前面我们已经讨论过此问题,便不用担心了。因此上面的代码会发生以下的变化:
[cpp]
view plain
copy
print?
void func(){
BookHandle bh(new Book());
...... //不用担心控制流如何离开
//bh的析构函数释放资源
}
但是也有一种情况使得RAII也变得不安全,那就是将RAII对象分配到堆上时。这时只有显示的使用delete来删除BookHandle对象才能让BookHandle对象的析构函数来释放其所包含的对象。
[cpp]
view plain
copy
print?
BookHandle* bh = new BookHandle(new Book()); //糟糕的主意
两个常用的RAII classes的对象是shared_ptr和auto_pt,前者通常是较好的选择。但是并非所有的资源都是heap-based,对于那种资源来说,像auto_ptr和shared_ptr往往不适合作为资源掌握者。既然如此,你可能需要建立自己的RAII calsses。对此还要注意它的copying的行为。一般而言,我们不允许对RAII class进行copy。但是事无绝对,如果你非要如此的话,请记住要对其进行深度拷贝。还要注意,每一个RAII class都应该提供一个“取得其所管理之资源”的办法。对原始资源的访问可能经由显示转换或隐式转换。显示转换比较安全,但隐式转换对客户比较方便。
相关文章推荐
- 使用RAII技术来管理资源
- 一种优雅的资源管理技术——RAII
- 资源管理技术 RAII
- 使用C++11新特性来实现RAII进行资源管理
- 使用RAII来管理对象资源
- 用RAII技术管理资源及其泛型实现
- 记录通用权限管理系统组件使用心得体会,写技术博客赢IPad2
- 使用Java ME技术开发手机密码管理软件(已发《电脑编程技巧和维护》11月上)
- 基于小型GIS技术的电力资源管理系统
- 自动资源释放-使用对象管理资源,解决资源泄露问题
- 可以永久免费下载、免费使用、免费升级、有QQ153585978群技术支持的通用权限管理系统组件【含免费代码生成器】
- C++箴言:使用对象管理资源
- Restlet实战(二)使用一个Application管理多个资源
- 如何使用 Mmcv.exe 工具来管理群集消息队列资源[转]
- 使用 apt-get 的時候,出现目录或者被锁住的解决办法(E: 无法获得锁 /var/lib/dpkg/lock - open (11: 资源临时不可用) E: 无法对管理目录(/var/lib/dpkg/)加锁,是不是另一个包管理)
- netbeans开发桌面应用程序时使用自动资源管理的一些纠结
- 使用Java ME技术开发手机密码管理软件
- yacc/lex windows 下 Parser Generator 使用指南 - linux技术 动漫资源--林木100
- 使用HGE时管理资源的问题..
- RAII技术--获取资源即初始化