请牢记:函数
一、复制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对象被复制,资源的拥有权从被复制物转移到目标物。