条款14: 在资源管理类中小心copying行为
(Think carefully about copying behavior in resource-managing classes.)
内容:
在上一款中我们谈到,用资源管理类来管理动态分配的资源及如何运用auto_ptr和tr1::share_ptr管理
heap-based资源来展示这个观点的,而在实际编写代码中,我们要用的资源不一定是来自heap,那么这样的
auto_ptr和tr1::share_ptr就不适合作为资源管理类,这个时候我们需要建立自己的资源管理类。
书上举了一个例子是互斥器对象mutex,那么mutex资源管理类就可以这么写:
class Mutex{...}; //资源mutex类
class Lock{
public:
explicit Lock(Mutex* pMutex):pcurMutex_(pMutex){
lock(pcurMutex_);
}
~Lock(){
unLock(pcurMutex_);
}
private:
Mutex* pcurMutex_;
};
接下来这么用:
Mutex m;
...
{
...
Lock autoLock(&m);//自动锁定mutex
... //区块结束时自动释放mutex
}
如果对象被复制,会发生什么情况?
Lock m1(&m);
Lock m2(m1);
这个时候你可能采用两种做法:
(1)禁止复制。如果你觉得这里的对象复制不合理的话就可以明确的禁止这种复制行为(将copy构造和copy
assign operator操作设置为私有成员).代码就这样写:
class Lock:private Uncopyable{
...
};
(2)对被管理资源作"引用计数"。这个和tr1::shared_ptr体现的观点是一样的。幸运的是由于shared_ptr可以
自行指定删除器,那么代码我们就可以这么写:
class Lock{
public:
explicit Lock(Mutex* pm):sptrMutex_(pm,unLock){
lock(sptrMutex_.get()); //锁住它的目标资源
}
private:
std::tr1::shared_ptr<Mutex > sptrMutex_;
};
对于管理资源的"复制行为",我们也可能采取下面两种策略实现(即在copy构造函数和赋值运算函数实现体内所
采取的策略):
(1)可以针对所管理的资源进行拷贝,也就是说,当你复制资源管理器的时候,你就对被管理资源实现了"深度
拷贝"。
(2)转移底部资源的拥有权。此时资源的拥有权会从被复制物转移到目标物。auto_ptr其实说明的就是这个观点。
好了,本条款讨论结束.
请记住:
◆ 复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为.
◆ 普遍而常见的RAII class copying行为是:抑制copying、施行引用计数法.不过其它行为也都可能被实现.