以对象的形式管理资源

题目来自[1]条款13:以对象管理资源。
因为太贴切了,所以直接用了。

首先说一下资源。

所有资源就是,一旦用了它,将来必须还给系统。[1]

而资源一般是[1]:

  • 内存
  • 文件描述器(file decriptors)
  • 互斥锁 (mutex locks)
  • 图形界面中的字型和笔刷
  • 数据库连接
  • 网络sockets

我们假设有个资源就叫做Resource 好了,它通过工厂函数(factory function)供应。

struct Resource
{
    int i;
};

Resource* createResource()
{
    return new Resource;
}

*按照惯例,虽然代码很简介,仅是为了演示使用

然后,正确地使用如下:

    Resource* ptr = createResource();
    ptr->i = 3;
    //... 或者中间做别的操作
    delete ptr; //或者再重新定义一个destroy回收函数

但是,需要时常记得手动去回收资源。然而,忘记这种事情不也经常发生吗?
更进一步地假设,在回收这个资源之前,如果抛出异常或者过早return了,那么资源也会被泄漏,像这样:

void doSomething(int i)
{
    Resource* ptr = createResource();
    // do something
    if(i <0) return; //这里return
    delete ptr;
}

也许没有人会直接写出这么赤裸裸地暴露智商的代码,
但是,当函数很长,而return 的那一句是后来维护的时候加上去的,没有考虑到后面的资源回收—也许他只是急于解决bug,而忽略了细节—-这就导致了严重的资源泄漏。

于是,我们有个美好的愿景,当资源的生命周期结束的时候,能够自动被回收 (其实就是其他语言中的垃圾回收装置)

生命周期结束?生命周期结束!
想到什么了吗,那就是析构函数。
析构函数在对象生命周期结束的时候自动执行。这个特性可以为我们管理资源。
所以,稍微修改一下就变成这样了:

struct Resource
{
    int i;
};

Resource* createResource()
{
    return new Resource;
}

class ResourceHandle
{
    Resource* pointer;

    //防止被copy
    ResourceHandle(const ResourceHandle&);
    ResourceHandle& operator = (const ResourceHandle&);
public:
    ResourceHandle(Resource* inp) : pointer(inp) {}
    ~ResourceHandle()
    {
        delete pointer;
    }
};

void doSomething(int i)
{
    ResourceHandle re(createResource());
    // do something
    if(i <0) return;
}

现在就能够正确地回收资源了。

这应该算是最简单原始的资源管理类了。
然而,我们在实际的使用中,还有更多的需求。比如说,我希望资源handle 能够被复制,能够传出函数体外,那怎么办呢?
有一个方法就是使用引用计数,当计数为0时,就自动回收资源。

很幸运,在这个站在巨人肩膀的时代上,我们发现了智能指针:share_ptr

这玩意是干嘛的?

share_ptr 的特性就是,采用引用计数,包含一个资源的handle(类似于资源的号码牌,或者任意能够通过它访问资源的东西,这里就是指针),当share_ptr 的生命周期结束时,减少引用数。如果这时候引用数为0,那么在析构函数中回收它。
当复制share_ptr 时,内部的handle 也会进行copy,相应地,引用计数当然也增加。
然而,使用不当地话,可能会发生循环引用,导致计数永远不会为0。从而资源泄漏

解决循环引用的方法是使用weak_ptr,这又是另外一个话题了,这里提一下就好。

使用share_ptr 要包含头文件

#include<tr1/memory>

于是,运用一下智能指针,代码又变为这样了:

void doSomething(int i)
{
    share_ptr<Resource> sptr( createResource() );
    //do something

}

除了share_ptr 外,还有auto_ptr,不过这个指针在C++11 中已经建议被弃用。感兴趣的话,倒是可以自己去了解一下。

对于使用指针,还有一点建议就是

以独立的语句,将newed 对象置入智能指针中

为什么?看[1] 条款17。

[参考资料]
[1] Scott Meyers 著, 侯捷译. Effective C++ 中文版: 改善程序技术与设计思维的 55 个有效做法[M]. 电子工业出版社, 2011.
(条款13:以对象管理资源;
条款17:以独立的语句,将newed 对象置入智能指针中)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值