假設我們使用c api函式處理型別為mutex的互斥器物件,共有lock和unlock兩函式可用:
void lock(mutex* pm); //鎖定pm所指的物件
void unlock(mutex* pm); //將互斥器解除鎖定
為確保絕不會忘記將乙個被鎖住的mutex解鎖,你可能會希望建立乙個class用來管理機鎖。這樣的class的基本結構由raii守則支配,也就是在「資源在構造期間獲得,在析構期間釋放」:
class lock
//獲得資源
~lock()
private:
mutex *mutexptr;
};
使用者對lock的用法符合raii方式:
mutex m; //定義你需要的互斥器
...
這很好,但如果lock物件被複製,會發生什麼?
lock m11(&m); //鎖定m
lock m12(m11); //將m11複製到m12身上,會發生什麼事?
這是某個一般化問題的特定例子。那個一般化的問題是每一位raii class作者一定需要需要面對的:「當乙個raii物件被複製,會發生什麼事?」 大多數時候你會選擇一下兩種可能:
(1)禁止複製。許多時候允許raii物件被複製並不合理。對乙個像lock這樣的class這是有可能的,因為很少能夠合理擁有「同步基礎器物」(synchronization primitives)的復件。如果複製動作對raii並不合理,你便應該禁止。可以將copying操作申明為private(見條款06)。對lock而言看起來是這樣:
class lock:private uncopyable;
(2)對底層資源祭出「引用計數法(reference-conut)」。有時候我們希望保有資源,直到它的最後乙個使用者被銷毀。這種情況下複製raii物件時,應該將資源的「被引用數」遞增。tr1::shared_ptr便是如此。
str::shared_ptr允許指定所謂的「刪除器」(deleter),那是乙個函式或函式物件,當引用次數為0時便被呼叫(auto不存在此機能,它總是將其指標刪除)。刪除器對tr1::shared_ptr建構函式而言是可有可無的第二引數。
class lock
private:
std::tr1::shared_ptrmutexptr; //使用shared_ptr替換raw pointer
};
(3)複製底部資源 某些標準字串型別是「指向heap記憶體」之指標構成*(那記憶體被用來存放字串的組成字元)。這種字串物件內含乙個指標指向heap記憶體。當這樣乙個字串物件被複製,不論指標或其所指記憶體都會被製作成乙個復件。這樣的字串展現深度複製行為。
(4)轉移底部資源的擁有權。某些罕見場合下你可能希望確保永遠只有乙個raii物件指向乙個未加工資源,即使raii物件被複製依然如此。此時資源的擁有權會被複製物轉移到目標物。
結論:複製raii物件必須一併複製它所管理的資源,所以資源的copying行為決定raii物件的copying行為。
普遍而常見的raii class copying行為是:抑制copying、施行應用計數法。不過其他行為也可能被實現。
條款14 在資源管理類中小心copying行為
結論1 複製raii物件必須一併複製它所管理的資源,所以資源的copying行為決定raii物件的copying行為。結論2 普遍而常見的raii class copying行為是 1 抑制copying,即禁止複製 很多時候允許raii物件被複製是不合理的。2 對底層資源施行引用計數法 在此情況下...
條款14 在資源管理類中小心copying行為
總結 條款13介紹了作為資源管理類支柱的 resource acquisition isinitialization raii 原則,並描述了 auto ptr 和 tr1 shared ptr 在基於堆的資源上運用這一原則的表現。然而,並非所有的資源都是基於堆的,對於這樣的資源,像 auto pt...
條款14 在資源管理類中小心copying行為
條款14 在資源管理類中小心copy行為 1.複製raii物件必須一併複製它所管理的資源,所以資源的copying行為決定raii物件的copying行為。2.普遍而常見的raii class copying行為是 抑制copying 施行引用計數法 reference counting 不過其他行...