条款14:在资源管理类中当心copying行为

请牢记:函数

一、复制RAII对象必须一并复制它所管理的资源,因此资源的copying行为决定RAII对象的copying行为。spa

二、广泛常见的RAII class copying行为是:抑制copying、施行引用计数法。不过其余行为也可能被实现。指针

 

auto_ptr和tr1::shared_ptr的观念表如今heap_based资源上。然而并不是全部资源都是heap_based,对于非heap_based资源而言,须要创建本身的资源管理类。对象

假设咱们使用C API函数出来类型为Mutex的互斥器对象(mutex objects),共有lock和unlock两个函数。blog

void lock(Mutex* pm);		//锁定pm所指的互斥器
void unlock(Mutex* pm);		//将互斥器解除锁定

为确保毫不会忘记将一个被锁住的Mutex解锁,建立一个Lock class 来管理机锁。这样的class的基本结构由RAII守则支配,也就是“资源在构造期间得到,在析构期间释放”:内存

class Lock
{
public:
	explicit Lock(Mutex* pm)
		: mutexPtr(pm)
	{
		Lock(mutexPtr);		//得到资源
	}
	~Lock()
	{
		unlock(mutexPtr);	//释放资源
	}
private:
	Mutex *mutexPtr;
};

客户对Lock的用法符合RAII方式:ci

Mutex m;
...
{
Lock ml(&m);    //锁定互斥器
...
}   //在区块末尾,自动解除互斥器锁定

若是此时Lock对象被复制:资源

Lock ml1(&m);    //锁定m
Lock ml2(ml1);   //将ml1复制到ml2上,会发生什么?

可能有如下两种选择:字符串

禁止复制:许多时候容许RAII对象复制并不合理:get

 

若是没有按须要定义复制构造函数和赋值操做符,那么获得的结果一般是:非内存资源被建立一次,释放屡次。
禁止方式:将copying操做声明为private。

class Lock : private Uncopyable  //禁止复制。见条款6
{ public: ...            //如前 };

若是须要复制,从新定义复制构造函数和赋值操做符是必须的。
怎么写它们是一个问题,具体的方案依赖于实际的须要,可使用深拷贝,也可使用相似于 shared_ptr 的引用计数机制,或者传递全部权。

对底层资源采用引用计数法

复制RAII对象时,将该资源的“被引用数”递增。例:shared_ptr。

shared_ptr的缺省行为是“当引用次数为0时删除所指物”,可是上面的例子咱们想要的动做是解除lock而非删除。
好在shared_ptr容许指定“删除器”:

class Lock
{
public:
    explicit Lock(Mutex* pm):mutexPtr(pm,unlock)  //以某个mutex初始化shared_ptr,并以unlock函数为删除器
    {lock(mutexPtr.get());}               //条款15

    ~Lock(){unlock(mutexPtr);}           //释放资源
private:
    std::tr1::shared_ptr<Mutex> mutexPtr;
};

深度拷贝:
某些标准字符串类型是“指向heap内存”之指针构成。这样的字符串对象被复制,不论指针或其所指内存都会被制做出一个复件。这样的字符串展示深度复制行为。

转移底部资源的拥有权:

auto_ptr奉行的复制意义:RAII对象被复制,资源的拥有权从被复制物转移到目标物。

相关文章
相关标签/搜索