一般來說,管理資源應該是沒有,可複製或有專門的拷貝語義的任何類。反過來也是如此:任何不可複製或需要特殊複製語義的類都是管理資源。在實踐中,C++語言中的「管理資源」意味着負責內存中的某些空間,或者連接到網絡或數據庫,或者文件句柄或撤銷事務等等。
資源管理捕獲了很多例子。這些職責是採取前綴操作,後綴操作以及可能的一些操作。例如,內存管理涉及獲取我們將要管理的內存地址的句柄,可能與該內存混亂,並最終釋放句柄(因爲如果你喜歡某事,就讓它免費)。
template<typename T>
struct memory {
memory(T const& val = T()) : p(new T(val)) { }
~memory() { delete p }
T& operator*() const { return *p; }
private:
T* p;
};
// ...
{
memory<int> m0;
*m0 = 3;
std::cout << *m0 << '\n';
}
這memory
類幾乎是正確的:它會自動獲取底層的內存空間,並自動將其釋放,即使異常傳播一段時間後,它收購了其資源。但考慮這樣的場景:
{
memory<double> m1(3.14);
memory<double> m2(m1); // m2.p == m1.p (do you hear the bomb ticking?)
}
因爲我們沒有爲memory
提供專門的複製語義中,編譯器提供了它自己的拷貝構造函數和拷貝賦值。這些做錯誤事情:m2 = m1
意味着m2.p = m1.p
,使這兩個指針指向相同的地址。這是錯誤的,因爲當m2
超出範圍時,它將其資源釋放爲一個好的責任對象,當m1
超出範圍時,它也釋放其資源,同一資源m2
已經釋放,完成雙重刪除 - 臭名昭着未定義的行爲場景。而且,在C++中,創建對象的副本是非常容易的,甚至不會注意到:函數根據值取其參數,按值返回它的參數,或者通過引用取其參數,然後調用另一個函數,該函數本身需要(或返回)參數值...更容易假設事情將試圖得到複製。
這一切都是說,當一個班級的理由是管理資源時,你應該立即知道你需要處理複製。你應該決定
- 你支持複製,而你決定的意思複製:資源的安全共享,進行底層資源的深層副本所以沒有共享任何或這兩種方法在copy-on-write合併或懶惰的副本。無論您選擇哪種路徑,您都需要提供專門的複製構造函數和複製賦值運算符。
- 或者您不支持任何形式的資源複製,在這種情況下您將禁用複製構造函數和複製賦值運算符。
我會走到目前爲止,並說資源管理是唯一的情況下,您禁用複製或提供專門的複製語義。這僅僅是The Rule of Three的另一個角度。
一個單就是一個例子。 – 2012-01-29 20:09:15