前言
</br>
在上一节的末尾,我已经提到RAII和智能指针并无直接关联,并且给出了例证。事实上,smart_ptr适用于管理heap-based资源。如果你所需要的资源不是heap-based,往往需要建立自己的资源管理类。
问题实例
</br>
假定我们有类型为murtex的互斥器对象,共有lock与unlock两个函数作用其上:1
2void lock(Mutex* pm);//锁定互斥器
void unlock(Mutex* pm);//解除锁定
基于RAII思想,我们建立一个资源管理类Lock:1
2
3
4
5
6
7
8class Lock{
public:
explicit Lock(Mutex* pm)
:mutexPtr(pm) {lock(mutexPtr);}
~Lock() {unlock(mutexPtr);}
private:
Mutex *mutexPtr;
}
如果资源管理类发生了复制行为1
2
3Mutex m;
Lock m1(&m);
Lock m2(m1);
将会产生何种后果?
资源管理类的复制行为
</br>
常见做法有以下两种:
- 禁止复制
有时允许RAII对象被复制并不合理,所以我们应该禁止它们的copy行为。如何禁止,详见Effective C++ 6 - 对底层资源使用引用计数
这种方法的最佳实现就是使用shared_ptr。通常我们只要内含一个shared_ptr成员变量,RAII classes便可以实现出reference-counting copying行为
引用计数在RAII中的应用
针对Lock class,可以把接受的指针从mutex*,转为shared_ptr<Mutex>。
但shared_ptr的default析构行为是“引用次数为0时删除所指物”,也就是析构时delete指针。(我们仅仅需要解除互锁)为了改变默认行为,我们必须手动地将删除器unlock作为shared_ptr的第二参数。具体实现如下:1
2
3
4
5
6
7
8class Lock{
public:
explicit Lock(Mutex* pm)
:mutexSP(pm,unlock) {lock(mutexSP.get());}
//无需析构函数
private:
shared_ptr<Mutex> mutexSP;
}
Lock类此时无需再声明析构函数,因为当shared_ptr析构时,unlock就会被调用。
总结
- 复制RAII对象必须一并复制它所管理的资源,资源的copying行为决定了RAII对象的copying行为。
- 对于RAII class copying,其常见做法无非是禁止拷贝和引用计数。