EffectiveC++-条款13:以对象管理资源

一. 内容

  1. 常见的资源有内存,文件描述器,互斥锁,图形字体和笔刷,数据库连接,网络等等。不论哪一种资源,一旦用了它,将来必须还给系统,否则会产生资源泄漏问题
  2. 尝试在任何情况下都确保正确的资源申请和释放是困难的,考虑到函数的多重返回路径,复杂的break,continue,goto等控制语句,或者程序维护员改动软件却未充分理解随之带来的冲击。
  3. 一个较好的解决方案是:基于对象进行资源管理,我们可以借助对象的生命周期,使用构造函数,析构函数,拷贝函数进行直接易懂的资源管理。
  4. 我们可以将资源放进对象中,当函数执行完毕,该对象会自动调用析构函数,释放那些资源。
  5. C++ 标准库中已经存在这样的对象,名为智能指针,但它其实是个像指针一样的对象,其析构函数自动对其所指对象调用 delete
    下面演示了如何使用 auto_ptr 避免资源泄漏的可能
    class Resource {
    public:
        Resource(int mData): Data(mData) {}
    public:
        int Data;
    };
    
    inline Resource* GetResource() {
        return new Resource(1);
    }
    
    inline void UseResource() {
    	//调用资源调度函数并使用auto_ptr智能指针进行管理
        const std::auto_ptr<Resource> ResourcePointer(GetResource());
        //常规使用资源
        std::cout << ResourcePointer->Data<<"\n";
        //块语句结束时,auto_ptr对象自动调用析构函数删除所指资源。
    }
    
  6. 这个例子展示了两个关键想法:
    • 获得资源后立刻放入管理对象。以上返回的资源被当作 auto_ptr 的初值,实际上这种做法常被称为:资源取得的时机便是初始化的时机,简称RAII,Resource Acquisition Is Initialization,当然也存在赋值的情况。
    • 管理对象运用析构函数确保资源被释放。无论函数以何种形式完成执行,对象在离开作用域后总是会被自动销毁,保证了资源的释放。条款8保证了异常不会脱离析构函数,我们不用担心异常的问题。
  7. 但是请注意智能指针的使用,当多个 auto_ptr 指向同一个对象,多个 auto_ptr 的销毁会导致对象被delete多次,导致未定义行为。
  8. auto_ptr 一个性质是:通过拷贝函数赋值或构造会转移资源所有权,原先 auto_ptr 指针资源变为null
        std::auto_ptr<Resource> ResourcePointerOne(GetResource());
        std::cout << ResourcePointerOne->Data << "\n";
        std::auto_ptr<Resource> ResourcePointerTwo = ResourcePointerOne;
        //ResourcePointerOne is nullptr
        std::cout << (ResourcePointerOne.get() == nullptr ? "nullptr" : "not nullptr") << "\n";
        //ResourcePointerTwo is not nullptr
        std::cout << (ResourcePointerTwo.get() == nullptr ? "nullptr" : "not nullptr") << "\n";
    
  9. auto_ptr 的替代方案是引用计数型智能指针,Reference-counting smart pointer(RCSP),RCSP会持续追踪共有多少对象指向某笔资源,并在无人指向它们的时候将其删除,并且可以多个智能指针指向同一资源,复制行为一如预期。但遗憾的是存在环形引用的情况,当两笔资源互指时,即使没人再使用它们,它们的引用数也不为0,导致资源泄漏。之后的 weak_ptr 解决了这个问题。
  10. 当然本条款重在强调对象管理资源的重要性,不在于智能指针的学习和使用,实际上现在 auto_ptr 已经被 unique_ptr 所替代。
  11. C++ 并没有针对动态分配的数组设计相应的智能指针,因为vector,string 几乎总是可以替换其行为,如果坚持,看看 Boost。
  12. 最后批注,上述演示 GetResource() 函数返回了未加工的指针,这简直是对资源泄漏的死亡邀约,因为调用者极易在这个指针上忘记调用 delete,我们将在条款18进行修改此接口。

二. 总结

  1. 为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源。
  2. 两个常被使用的RAII classes分别是tr1::shared_ptr和auto_ptr。前者通常是较佳的选择,因为其copy行为比较直观。若选择auto_ptr,复制动作会使它(被复制物)指向null。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值