题目来自[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 对象置入智能指针中)