Guru of the Week 條款11:物件等同(Object Identity)問題 (轉)

worldblog發表於2007-12-10
Guru of the Week 條款11:物件等同(Object Identity)問題 (轉)[@more@]

GotW #11 ntity

著者:Herb Sutter 

翻譯:kingofark

[宣告]:本文內容取自網站上的Guru of the Week欄目,其著作權歸原著者本人所有。譯者kingofark在未經原著者本人同意的情況下翻譯本文。本翻譯內容僅供自學和參考用,請所有閱讀過本文的人不要擅自轉載、傳播本翻譯內容;本翻譯內容的人請在閱讀瀏覽後,立即刪除其。譯者kingofark對違反上述兩條原則的人不負任何責任。特此宣告。

Revision 1.0

Guru of the Week 條款11:等同(Object Identity)問題:namespace prefix = o ns = "urn:schemas--com::office" />

難度:5 / 10

(“我到底是誰?”這個問題蘊含著如何確定兩個指標是否真的指向同一個物件的問題)

 

[問題]

測試語句“this != &other” 是一個防止自賦值(self-assingment)的常見編碼手法。那麼,要到達這個“防止自賦值(self-assingment)”目的,現有的語句是否是必要的和/或充分的呢?為什麼?或者為什麼不?如果答案是否定的,你又如何進行修改呢?注意要區分“protecting against Murphy vs. protecting against Machiavelli”。(* 譯註:見本條款末尾)

  T& T::operator=( const T& other ){


  if( this != &other ) {  // the test in question


  // ...


  }


  return *this;


  }


 

[解答]

一個簡短的解答:從技術上來看,它既不是必要的也不是充分的。在實踐當中,它工作得頗好但也有可能在C++標準中被修改。

 

 * 論點:異常-(Murphy

  如果operator=()是異常-安全的(exception-safe),那麼你並不需要檢查自賦值(self-assignment)。這裡有兩個上的不利因素:a)如果可以進行自賦值(self-assignment)檢查的話,那就可以進行徹底的從而省略掉賦值操作;b)如果程式碼被寫成異常-安全的(exception-safe),那麼同時也使得程式碼損失了一部分效率(這也即是說“paranoia has a price principle”,意即“偏執狂也有權衡代價的原則”)。

 

* 不是論點的論點:多重繼承

過去曾有人把多重繼承與本條款討論的問題聯絡起來,但實際上這個問題與多重繼承沒有任何關係。我們的討論的是一個涉及到C++標準怎樣讓你比較兩個指標的技術性問題。

 

* 論點:運算子的過載(Machiavelli

雖然一些類可能會提供它們自己的operator&(),但是問題中對自賦值(self-assignment)的檢查卻很可能不如你所期望的那樣運作,而是做一些完全不同的事情。用“protecting against Machiavelli”來意寓這種情況是因為,我們只能推測編寫operator=()的人也許大概知道他實現的類是不是也過載了operator&()。

要注意,一個類可能也會提供一個T::operator!=(),但這與本問題無關——它並不影響我們對自賦值(self-assignment)的檢查,原因是:由於一個被過載的運算子至少有一個引數的型別必須是“類(class)”型別,因而我們不可能編寫一個包含有兩個T*型引數的T::operator!=()。

 

後記1

下面是一個所謂的“程式碼(code joke)”。信不信由你,竟然真有一些並無惡意但無疑是被誤導了的程式碼編寫者曾企圖使用這樣的程式碼:

 T::T( const T& other ) {

  if( this != &other ) {

  // ...

  }

}

 怎麼樣?你能第一眼就看出毛病嗎?

 

後記2

  值得注意的是,還有另外一些情況,在這些情況當中,指標的比較也不是多數人光憑直覺就能考慮周到的。比如:

1.  James Kanze指出,把指標比較成字串的行為是未定義的。其原因(我還未見有人給出過)是C++標準明確規定:允許將字串存放在重疊的區域以作為一種空間最佳化方案。

2.  一般來說,雖然像諸如和>=等內建(built-in)運算子的運算結果在各種特定情況下(比如,同一個陣列中的兩個指向物件的指標)都有著良好的定義,但你還是不能用這些運算子對任意的指標進行比較。標準庫的使用也是基於這種限制的,其中規定:less<>以及其它庫必須給出各指標的次序(ordering),以使得我們可以建立,比方說,一個key為指標型別的map,即map>。(譯註:此處的map是STL的一部分,一個map包括key和value兩部分,使用的時候需要#include

 

(* 譯註:關於Murphy和Machiavelli,侯捷先生在其系列書評的《C++/大系》中提到:“就我的英文程度而言,[Sutter99](即《Exceptional C++》)讀起來不若[Meyers96] (即《More Effective C++》)和[Meyers98] (即《Effective C++2/e》)那般平順,原因是其中用了很多釐語、口語、典故。舉個例子,Morphy law是什麼,大家知道嗎?(莫菲定律說:會出錯的,一定會出錯。)Machiavelli又代表了什麼意思?(義大利政治家,以詐術聞名。)”

在這裡,本條款的譯者kingofark只能慚愧的說kingofark自己也沒有完全理解本條款使用Murphy和Machiavelli兩個詞的用意。

Machiavelli:馬基雅維利,尼克爾1469-1527義大利政治理論家,他的著作 君主論(1513年)闡述了一個意志堅定的統治者不顧道德觀念的如何獲得並保持其權力;馬基雅弗利,義大利新興資產階級思想政治家,歷史學家。)


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990914/,如需轉載,請註明出處,否則將追究法律責任。

相關文章