Guru of the Week 條款22:物件的生存期(第一部分) (轉)
GotW #22 Lifetimes – Part I:namespace prefix = o ns = "urn:schemas--com::office" />
著者:Herb Sutter
翻譯:K ][ N G of @rk™
[宣告]:本文內容取自網站上的Guru of the Week欄目,其著作權歸原著者本人所有。譯者kingofark在未經原著者本人同意的情況下翻譯本文。本翻譯內容僅供自學和參考用,請所有閱讀過本文的人不要擅自轉載、傳播本翻譯內容;本翻譯內容的人請在閱讀瀏覽後,立即刪除其。譯者kingofark對違反上述兩條原則的人不負任何責任。特此宣告。
Revision 1.0
Guru of the Week 條款22:的生存期(第一部分)
難度:5 / 10
(“生存,還是滅亡……[譯註:這是莎士比亞所著《哈姆雷特》中的名句]” 一個物件何時才算是真實存在的?這個問題用來考察一個物件何時才能被的使用。)
[Problem]
[問題]
評述下面的段。#2處的程式碼使安全和/或合法的嗎?請對你的回答做出解釋。
void f() {
T t(1);
T& rt = t;
// #1: 使用t或者rt做一些事情
t.~T();
new (&t) T(2);
// #2: 使用t或者rt做一些事情
} // t被再次銷燬
[解答]
是的,#2處的程式碼是安全且合法的(如果只考慮這部分程式碼的話),但:
a) 作為一個整體,它是不安全的,而且
b) 這樣做是一個壞習慣。
[為什麼#2是安全的(如果只考慮這部分程式碼的話)?]
C++標準草案明確規定,允許這種程式碼出現。現場的析構和重構造(in-place destruction and reconstruction)不會使rt這個引用失效。(當然,你不能在t.~T()與placement new之間使用t或rt,因為在那段時期裡不存在任何物件。我們還假設T::operator&()沒有被過載,即沒有被用來做「返回物件之地址」以外的其它事情。)
我們之所以說“如果只考慮這部分程式碼的話,#2就是安全的”,是因為f()作為一個整體而言,可能不是異常安全的(exception-safe):
[為什麼函式是不安全的?]
如果在T(2)的時候,T的建構函式有丟擲異常的可能,那麼f()就不是異常安全的。考慮其原因:如果T(2)丟擲異常,那麼在原來’t’所在的區域中將不會有新的物件被構造,而在函式末尾T::~T()仍然被正常呼叫(因為t是一個自動變數[automatic variable]),而且正如程式碼中的註釋所述,“t被再次銷燬”。這即是說,’t’會被構造一次,卻被銷燬兩次(嗚呼呀)。這將導致容易產生無法預見的副作用,比如core dumps。
[為什麼這是個壞習慣?]
如果忽略異常安全性的問題,那麼程式碼在這樣的設定下恰好就能夠正常工作,這是因為程式設計師此時知道被構造和銷燬之物件的具體型別。這即是說,該物件是一個T,並被作為一個T來被銷燬和重新構造。
在實際的程式碼中,這種技術(即便真是編碼所需)幾乎不會被使用,並且這樣做也是非常壞的習慣;原因是:如果其出現在成員函式中,那麼其將會充滿(有時難以捉摸的)危險:
void T::f( int i ) {
this->~T();
new (this) T(i);
}
現在這種技術還算安全嗎?基本上來說,不安全。考慮下面的程式碼:
class U : /*...*/ public T { /* ... */ };
void f() {
/*AAA*/ t(1);
/*BBB*/& rt = t;
// #1: 使用t或者rt做一些事情
t.f(2);
// #2: 使用t或者rt做一些事情
} // t被再次銷燬
如果”/*AAA*/”是”T”,那麼#2處的程式碼仍然可行,即使”/*BBB*/”不是”T”( ”/*BBB*/”可能是T的基類)。
如果”/*AAA*/”是”U”(譯註:而不是”T”),那麼無論”/*BBB*/”是什麼,都已經毫無懸念了。大概你所能期待的最好結果就是一個及時的core dump,因為對t.f()的呼叫將物件“切割(slices)”了。這裡說的“切割”是指:t.f()用屬於另一個不同型別的物件替換了原來的物件——這即是說函式使用了T而不是U。即便是你意欲編寫不可移植的程式碼,你也無法知曉「當原來U所在的記憶體區域被T物件之資料抹蓋以後,其被作為U是否還可用?」。固然還是有情況尚佳的機率,但是請不要走到那個地步……這絕不是一次良好的實踐。
本期GotW包含了一些基本的、有關現場析構和重構(in-place destruction and reconstruction)的安全性問題和切割問題。這為下期的“GotW條款23:物件生存期(第二部分)”作下鋪墊。
(完)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-991265/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Guru of the Week 條款23:物件的生存期(第二部分) (轉)物件
- Guru of the Week 條款13:物件導向程式設計 (轉)物件程式設計
- Guru of the Week 條款11:物件等同(Object Identity)問題 (轉)物件ObjectIDE
- Guru of the Week 條款19:自動轉換 (轉)
- Guru of the Week 條款27:轉呼叫函式 (轉)函式
- Guru of the Week 條款20:程式碼的複雜性(第一部分) (轉)
- Guru of the Week 條款28:“Fast Pimpl”技術 (轉)AST
- Guru of the Week 條款09:記憶體管理(上篇) (轉)記憶體
- Guru of the Week 條款10:記憶體管理(下篇) (轉)記憶體
- Guru of the Week 條款24:編譯級防火牆 (轉)編譯防火牆
- Guru of the Week 條款30附錄:介面原則 (轉)
- Guru of the Week 條款07:編譯期的依賴性 (轉)編譯
- Guru of the Week 條款14:類之間的關係(上篇) (轉)
- Guru of the Week 條款15:類之間的關係(下篇) (轉)
- Guru of the Week 條款05:覆寫虛擬函式 (轉)函式
- Guru of the Week 條款21:程式碼的複雜性(第二部分) (轉)
- Guru of the Week 條款16:具有最大可複用性的通用Containers (轉)AI
- Guru of the Week 條款08:GotW挑戰篇——異常處理的安全性 (轉)Go
- C++ articles:Guru of the Week #1 (轉)C++
- Guru of the week:#18 迭代指標. (轉)指標
- Guru of the week:#17 型別對映. (轉)型別
- Guru of The week #20 程式碼的複雜性 Ⅰ. (轉)
- Guru of the week:#19 自動型別轉換. (轉)型別
- C++ articles:Guru of the Week #4 -- Class Mechantics (轉)C++
- Guru of the Week #5:虛擬函式的重新定義 (轉)函式
- C++ articles:Guru of the Week #3:使用標準庫 (轉)C++
- More Effective C++ 條款22 (轉)C++
- C++ Gotchas 條款63:Member New和Member Delete之生存期與活動空間的迷惑 (轉)C++Godelete
- 條款13 以物件管理資源物件
- More Effective C++ 條款4 (轉)C++
- More Effective C++ 條款19 (轉)C++
- More Effective C++ 條款6 (轉)C++
- More effective C++ 條款14 (轉)C++
- More Effective C++ 條款15 (轉)C++
- More Effective C++ 條款2 (轉)C++
- More Effective C++ 條款3 (轉)C++
- More Effective C++ 條款11 (轉)C++
- More effective C++ 條款13 (轉)C++