您的位置:首页 > 大数据 > 人工智能

使用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都应该提供一个“取得其所管理之资源”的办法。对原始资源的访问可能经由显示转换或隐式转换。显示转换比较安全,但隐式转换对客户比较方便。 
     
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: