Guru of the Week 條款22:物件的生存期(第一部分)
GotW #22 Object Lifetimes – Part I<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
著者:Herb Sutter
翻譯:K ][ N G of @rk™
[宣告]:本文內容取自www.gotw.ca網站上的Guru of the Week欄目,其著作權歸原著者本人所有。譯者kingofark在未經原著者本人同意的情況下翻譯本文。本翻譯內容僅供自學和參考用,請所有閱讀過本文的人不要擅自轉載、傳播本翻譯內容;下載本翻譯內容的人請在閱讀瀏覽後,立即刪除其備份。譯者
Revision 1.0
Guru of the Week條款22:物件的生存期(第一部分)
難度:5 / 10
(“生存,還是滅亡……[譯註:這是莎士比亞所著《哈姆雷特》中的名句]” 一個物件何時才算是真實存在的?這個問題用來考察一個物件何時才能被安全的使用。)
[Problem]
[問題]
評述下面的程式段。#2處的程式碼使安全和/或合法的嗎?請對你的回答做出解釋。
[解答]
是的,#2處的程式碼是安全且合法的(如果只考慮這部分程式碼的話),但:
a)函式作為一個整體,它是不安全的,而且
b)這樣做是一個壞習慣。
[
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來被銷燬和重新構造。
在實際的程式碼中,這種技術(即便真是編碼所需)幾乎不會被使用,並且這樣做也是非常壞的習慣;原因是:如果其出現在成員函式中,那麼其將會充滿(有時難以捉摸的)危險:
現在這種技術還算安全嗎?基本上來說,不安全。考慮下面的程式碼:
如果”/*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:物件生存期(第二部分)”作下鋪墊。
(完)
相關推薦
Guru of the Week 條款20:程式碼的複雜性(第一部分)
GotW #20 Code Complexity – Part I<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 著者:Herb Sutter 翻譯:K ][
Guru of the Week 條款21:程式碼的複雜性(第二部分)
GotW #21 Code Complexity – Part II<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 著者:Herb Sutter 翻譯:K ]
Guru of the Week 條款22:物件的生存期(第一部分)
GotW #22 Object Lifetimes – Part I<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 著者:Herb Sutter 翻譯:K ]
Guru of the Week 條款09:記憶體管理(上篇)
GotW #09 Memory Management - Part I 著者:Herb Sutter 翻譯:kingofark [宣告]:本文內容取自www.gotw.ca網站上的Guru of the Week欄目,其著作權歸原著者本人所有。譯者kingofark在未經
Guru of the Week 條款06:正確使用const
GotW #06 Const-Correctness 著者:Herb Sutter 翻譯:kingofark [宣告]:本文內容取自www.gotw.ca網站上的Guru of the Week欄目,其著作權歸原著者本人所有。譯者kingofark在未經原著者本人同意的情
Guru of the Week 條款08:GotW挑戰篇——異常處理的安全性
GotW #08 CHALLENGE EDITION Exception Safety 著者:Herb Sutter 翻譯:kingofark [宣告]:本文內容取自www.gotw.ca網站上的Guru of the Week欄目,其著作權歸原著者本人所有。譯者king
Guru of the Week 條款16:具有最大可複用性的通用Containers
GotW #16 Maximally Reusable Generic Containers<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />著者:Herb Sutter翻譯:kingofar
Guru of the Week 條款30附錄:介面原則
它是這麼工作的:所謂“名稱搜尋”就是當你寫下一個“f(parm)”呼叫時,編譯器必須要決策出你想調哪個叫f的函式。(由於過載和作用域的原因,可能會有幾個叫f的函式。)Koenig lookup是這麼說的,如果你傳給函式一個class型別的實參(此處是parm,型別為NS::T),為了查詢這個函式名,編譯器被要
Guru of the Week 條款01: 變數的初始化
GotW #01 Variable Initialization 著者:Herb Sutter 翻譯:kingofark [宣告]:本文內容取自www.gotw.ca網站上的Guru of the Week欄目,其著作權歸原著者本人所有。譯者kingofark在未經原著者本人
c++11 條款22:當使用Pimpl(指向實現的指標)時,在實現檔案裡定義特定的成員函式
條款22:當使用Pimpl(指向實現的指標)時,在實現檔案裡定義特定的成員函式 假如你曾經和過多的編譯構建時間抗爭過,你應該熟悉Pimpl(指向實現的指標)這個術語。這項技術是你可以把類的資料成員替換成一個指向實現類(結構)的指標,把原來在主類中的資料成員
Buggy Java Code:Java程式設計師最容易犯的10個錯(第一部分)
翻譯:叩丁狼教育吳嘉俊 Java語言最開始是為了互動電視機而開發的,隨著時間的推移,他已經廣泛應用各種軟體開發領域。基於面向物件的設計,遮蔽了諸如C,C++等語言的一些複雜性,提供了垃圾回收機制,平臺無關的虛擬機器技術,Java創造了一種前所未有的開發方式。另一方面,得益於Java提出的“一次編
Spring Boot 專欄:HelloWord快速入門(第一講)
寫在前面的話: 沒有好的文采,但是有一顆樂於分享心,希望用最精簡的語言,描繪每一個demo的構建過程,為開發者提供最容易上手的demo樣例。 SpringBoot簡介 Spring Boot來簡化Spring應用開發,約定大於配置, 去繁從簡(大體和SpringMv
ORBSLAM2學習(四):DBoW2原始碼分析(OrbVocabulary部分)
{(w1,weight1),(w2,weight2),...,(wn,weightn)}的形式,就對應著這裡的BowVector。BowVector派生自public std::map<WordId, WordValue>,實際上就是public std::map<int, double&g
java核心(十二):多線程(第一篇)
實用 implement cti size timer類 離開 syn ace final 一、多線程的實現方式 Java多線程實現方式主要有三種:繼承Thread類、實現Runnable接口、實現Callable接口通過FutureTask包裝器來創建Thread線程。
effective c++條款22:將成員變數宣告為private
將成員變數宣告為private的三大理由: 1. 提供語法一致性: 如果將所有的變數都宣告為private,那麼當其他人使用這個類時,就不用糾結是以函式方式呼叫還是變數方式呼叫,更加節省時間。 #include <iostream> using namespa
PyDev of the Week: Jacqueline Kazil
This week we welcome Jacqueline Kazil (@JackieKazil) as our PyDev of the Week! She is the co-author of Data Wrangling with Python. Jacqueline is the creato
NRN video of the week: Burger King taps into artificial intelligence for new ads
Burger King has launched a new campaign with the "first ads entirely created by an A.I. to air on national television," according to a Sept. 27 release fro
PyDev of the Week: K Lars Lohn
This week we welcome K Lars Lohn (@2braids) as our PyDev of the Week! He has been a part of the Python community for quite a few years. You can learn a bit
PyDev of the Week: Marc Garcia
This week we welcome Marc Garcia (@datapythonista) as our PyDev of the Week! Marc is a core developer of pandas, a Python data analysis library. If you’d l
Marginally Interesting: Tool of the week (web edition): gotapi.com
Tweet This weeks tool of the week (well, not that every week actually g