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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- NewStarCTF 2023 公開賽道 WEEK4|MISC 部分WP
- 物件的生存期 記憶體 深度複製 複製建構函式 筆記物件記憶體函式筆記
- 條款04: 確定物件被使用前已被初始化物件
- 第一條
- Mac Backup Guru for Mac(備份工具)Mac
- 第22條:理解NSCopying協議協議
- 22. 物件導向之多型物件多型
- 變數的儲存方式和生存期變數
- 初識BOM及其部分物件物件
- NewStarCTF 2023 公開賽道 做題隨筆(WEEK1|MISC部分)
- 第22章 物件共享,避免建立多物件——享元模式物件模式
- JS json字串轉物件、物件轉字串JSON字串物件
- 資料千萬條,安全第一條
- [Gold week hot : 掘金一週熱門] 第一期Go
- jquery物件和DOM物件的互相轉換jQuery物件
- 學習進度條2024-05-22
- 【C進階】22、條件編譯分析編譯
- 第一條隨筆
- 第一條部落格
- 【CSS系列】命名千萬條,BEM第一條CSS
- 【JQuery】DOM物件和JQuery物件的互相轉換jQuery物件
- 類和物件部分知識總結物件
- 物件轉型物件
- [譯]Workcation App – 第一部分 . 自定義 Fragment 轉場動畫APPFragment動畫
- FPGA的DAC轉換部分遇到的問題FPGA
- xlua中lua物件到c#物件的轉型物件C#
- 小遊戲重回第一品類 22款產品登上阿拉丁8月TOP榜單遊戲
- jquery物件如何轉化成DOM物件jQuery物件
- 20款前端特效及部分原始碼前端特效原始碼
- nowcoder Week Contest
- Week 4 Problems
- Week 11 Problems
- ARTS Week 20
- Linux 探索之旅 | 第三部分第一課:資料處理,慢條斯理Linux
- 《看雪服務條款》
- Redis | 第一部分:資料結構與物件 上篇《Redis設計與實現》Redis資料結構物件
- Redis | 第一部分:資料結構與物件 下篇《Redis設計與實現》Redis資料結構物件
- 查詢條件封裝物件封裝物件
- 一些轉儲和清除記憶體物件和物理物件的命令(轉)記憶體物件