More Effective C++ 條款20 (轉)

worldblog發表於2007-12-10
More Effective C++ 條款20 (轉)[@more@]

條款20:協助完成返回值:namespace prefix = o ns = "urn:schemas--com::office" />

一個返回的很難有較高的,因為傳值返回會導致物件內的構造和解構函式(參見條款19),這種呼叫是不能避免的。問題很簡單:一個函式要麼為了保證正確的行為而返回物件要麼就不這麼做。如果它返回了物件,就沒有辦法擺脫被返回的物件。就說到這。

考慮rational(有理數)類的成員函式operator*:

class Rational {

public:

  Rational(int numerator = 0, int denominator = 1);

  ...

  int numerator() const;

  int denominator() const;

};

 

// 有關為什麼返回值是const的解釋,參見條款6,

const Rational operator*(const Rational& lhs,

  const Rational& rhs);

甚至不用看operator*的程式碼,我們就知道它肯定要返回一個物件,因為它返回的是兩個任意數字的計算結果。這些結果是任意的數字。operator*如何能避免建立新物件來容納它們的計算結果呢?這是不可能的,所以它必須得建立新物件並返回它。不過C++員仍然花費大量的精力尋找傳說中的方法,能夠去除傳值返回的物件(參見Effective C++ 條款23和條款31)。

有時人們會返回指標,從而導致這種滑稽的句法:

// 一種不合理的避免返回物件的方法

const Rational * operator*(const Rational& lhs,

  const Rational& rhs);

 

Rational a = 10;

Rational b(1, 2);

 

Rational c = *(a * b);  //你覺得這樣很“正常”麼?

它也引發出一個問題。呼叫者應該刪除函式返回物件的指標麼?答案通常是肯定的,並且通常會導致資源洩漏。

其它一些開發人員會返回引用。這種方法能產生可接受的句法,

//一種危險的(和不正確的)方法,用來避免返回物件

const Rational& operator*(const Rational& lhs,

   const Rational& rhs);

 

Rational a = 10;

Rational b(1, 2);

 

Rational c = a * b;  // 看上去很合理

但是函式不能被正確地實現。一種嘗試的方法是這樣的:

// 另一種危險的方法 (和不正確的)方法,用來

// 避免返回物件

const Rational& operator*(const Rational& lhs,

  const Rational& rhs)

{

  Rational result(lhs.numerator() * rhs.numerator(),

  lhs.denominator() * rhs.denominator());

  return result;

}

這個函式返回的引用,其指向的物件已經存在了。它返回的是一個指向區域性物件result的引用,當operator* 退出時result被自動釋放。返回指向已被釋放的物件的引用,這樣的引用絕對不能使用。

相信我:一些函式(operator*也在其中)必須要返回物件。這就是它們的執行方法。不要與其對抗,你不會贏的。

你消除傳值返回的物件的努力不會獲得勝利。這是一場錯誤的戰爭。從效率的觀點來看,你不應該關心函式返回的物件,你僅僅應該關心物件的開銷。你所應該關心的是把你的努力引導到尋找減少返回物件的開銷上來,而不是去消除物件本身(我們現在認識到這種尋求是無用的)。如果沒有與這些物件相關的開銷,誰還會關心有多少物件被建立呢?

以某種方法返回物件,能讓消除臨時物件的開銷,這樣編寫函式通常是很普遍的。這種技巧是返回constructor argument而不是直接返回物件,你可以這樣做:

// 一種高效和正確的方法,用來實現

// 返回物件的函式

const Rational operator*(const Rational& lhs,

  const Rational& rhs)

{

  return Rational(lhs.numerator() * rhs.numerator(),

  lhs.denominator() * rhs.denominator());

}

仔細觀察被返回的。它看上去好象正在呼叫Rational的建構函式,實際上確是這樣。你透過這個表示式建立一個臨時的Rational物件,

Rational(lhs.numerator() * rhs.numerator(),

  lhs.denominator() * rhs.denominator());

並且這是一個臨時物件,函式把它複製給函式的返回值。

返回constructor argument而不出現區域性物件,這種方法還會給你帶來很多開銷,因為你仍舊必須為在函式內臨時物件的構造和釋放而付出代價,你仍舊必須為函式返回物件的構造和釋放而付出代價。但是你已經獲得了好處。C++規則允許編譯器最佳化不出現的臨時物件(temporary s out of existence)。因此如果你在如下的環境裡呼叫operator*:

Rational a = 10;

Rational b(1, 2);

 

Rational c = a * b;  // 在這裡呼叫operator*

編譯器就會被允許消除在operator*內的臨時變數和operator*返回的臨時變數。它們能在為目標c分配的裡構造return表示式定義的物件。如果你的編譯器這樣去做,呼叫operator*的臨時物件的開銷就是零:沒有建立臨時物件。你的代價就是呼叫一個建構函式――建立c時呼叫的建構函式。而且你不能比這做得更好了,因為c是命名物件,命名物件不能被消除(參見條款22)。不過你還可以透過把函式宣告為inline來消除operator*的呼叫開銷(不過首先參見Effective C++ 條款33):

// the most efficient way to write a function returning

// an object

inline const Rational operator*(const Rational& lhs,

  const Rational& rhs)

{

  return Rational(lhs.numerator() * rhs.numerator(),

  lhs.denominator() * rhs.denominator());

}

“好,不錯”,你嘀咕地說,“最佳化,誰關心編譯器能做什麼?我想知道它們確實做了什麼,Does any of this nonsense work with real compilers? It does。這種特殊的最佳化――透過使用函式的return location(或者用一個在函式呼叫位置的物件來替代),來消除區域性臨時物件――是眾所周知的和被普遍實現的。它甚至還有一個名字:返回值最佳化(return value optimization)。實際上這種最佳化有自己的名字本身就可以解釋為什麼它被廣泛地使用。尋找C++編譯器的程式設計師會問銷售商編譯器是否有返回值最佳化功能。如果一個銷售商說有而另一個問“那是什麼東西?”,第一個銷售商就會有明顯的競爭優勢。啊,資本主義,有時你實在應該去愛它。(謹代表作者觀點,譯者堅決擁護四項基本原則  譯者注  :-) )

 

 

 

附錄:

文中最後一段黑體部分如何翻譯,我有些拿不準,請高手告知,為了容易理解,我在此附上此文最後一段的英文原文:

"Yeah, yeah," you mutter, "optimization, schmoptimization. Who cares what compilers can do? I want to know what they do do. Does any of this nonsense work with real compilers?" It does. This particular optimization — eliminating a local temporary by using a function's return location (and possibly replacing that with an object at the function's call site) — is both well-known and commonly implemented. It even has a name: the return value optimization. In fact, the existence of a name for this optimization may explain why it's so wly available. Programmers looking for a C++ compiler can ask vendors whether the return value optimization is implemented. If one vendor says yes and another says "The what?," the first vendor has a notable competitive advantage. Ah, ctalism. Sometimes you just gotta love it.


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

相關文章