Item 14:Think carefully about copying behavior in resource-managing classes
條款13導入這樣的觀念:“資源取得時機便是初始化時機”,並以此作爲“資源管理類”的脊柱。然而當一個RAII對象被複制,會發生什麼事?大多數時候你會選擇以下四種可能。
禁止複製:許多時候允許RAII對象被複制並不合理,因爲很少能夠合理擁有“同步化基礎器物”的復件(副本)。如果複製動作對RAII class並不合理,你便應該禁止之。條款6告訴你怎麼做:將copying操作聲明爲private。
對底層資源祭出“引用計數法”:有時候我們希望保有資源,直到它的最後一個使用者(某對象)被銷燬。這種情況下複製RAII對象時,應該將資源的“被引用數”遞增。tr1:shared_ptr便是如此。
tr1:shared_ptr允許指定所謂的“刪除器”,那是一個函數或函數對象,當引用次數爲0時便被調用。刪除器對tr1:shared_ptr構造函數而言是可有可無的第二參數,所以代碼看起來像這樣:
/*假設我們使用C API函數處理類型爲Mutex的互斥器對象,共有lock和unlock函數可用:
void lock(Mutex* pm); //鎖定pm所指的互斥器
void unlock(Mutex* pm); //將互斥器解除鎖定
爲確保絕不會忘記將一個被鎖住的Mutex解鎖,我們建立這樣一個class用來管理機鎖*/
class Lock
{
public:
explicit Lock(Mutex* pm):mutexPtr(pm,unlock)
{
lock(mutexPtr.get());
}
private:
std::tr1::shared_ptr<Mutex> mutexPyr;
}
複製底部資源:你需要“資源管理類”的唯一理由是,當你不再需要某個復件時確保它被釋放。在此情況下複製資源管理對象,應該同時也複製其所包覆的資源。也就是說,複製資源管理對象時,進行的是深度拷貝。
轉移底部資源的所有權:某些罕見場合下你可能希望確保永遠只有一個RAII對象指向一個未加工資源,即使RAII對象被複制依然如此,此時對象的所有權會從被複制物轉移到目標物。
copying函數可能被編譯器自動創建出來,因此除非編譯器所生版本做了你想要做的事,否則你得自己編寫它們。
請注意:
1.複製RAII對象必須一併複製它所管理的資源,所以資源的copying行爲決定RAII對象的copying行爲。
2.普遍而常見的RAII class copying行爲是:抑制copying、施行引用計數法。不過其他行爲也都可能被實現。