請牢記:函數
一、複製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對象被複制,資源的擁有權從被複制物轉移到目標物。