效率 條款20 協助完成「返回值優化(RVO)」

2021-07-10 04:40:37 字數 1523 閱讀 3965

函式如果返回物件,對效率狂而言是乙個嚴重的挫折,因為以by-value方式返回物件,背後隱藏的constructor和destructor都將無法消除。

有的人會返回指標,於是導致下列這種拙劣的語法形式:

const rational* operator*(const rational* lhs,const rational* rhs)

她會引出乙個重要的問題,導致記憶體洩漏的問題。
另一些程式設計師可能會返回reference,於是到處乙個危險的做法:

const rational& operator*(const rational* lhs,const rational* rhs)

此函式返回乙個reference,指向乙個不再存在的物件,更明確的說,它返回乙個reference指向區域性物件result,但該區域性物件在返回時自動被銷毀了,導致返回乙個reference指向乙個不存在的物件。
總的來說:如果函式一定得以by-value方式返回乙個物件,你絕對無法消除之。這是一場錯誤的戰爭從效率的眼光來看,你不應該在乎函式返回了乙個物件,你應該在乎的是那個物件的成本幾何。你需要做的事女里找出某種方法來降低返回物件的成本,而不是想盡辦法消除物件本身。

我們可以用某種特殊寫法來撰寫函式,使它在返回物件時,能夠讓編譯器消除臨時物件的成本。我們的伎倆是:返回所謂的constructor arguments(構造函式引數)一取代物件。如:

函式一:const rational operator*(const rational* lhs,const rational* rhs)

函式二:const rational& operator*(const rational* lhs,const rational* rhs)

以上兩者的區別在於函式一多建立了乙個臨時物件。而函式二僅僅建立了乙個臨時物件。函式二具體的做法是以constructor arguments取代區域性物件,當作返回值。

如果你這樣呼叫時: 

rational a=10;

rational b(1,2);

rational c=a*b;

c++則會允許編譯器將臨時物件優化使它們不存在。如上面公式所寫,比的編譯器會消除operator*內的臨時物件及被operator*返回的臨時物件。它們可以將return表示式所定義的物件構造於c的記憶體內。如果編譯器這樣做,你呼叫operator*時的臨時物件總成本為0也就是說沒有任何臨時物件需要被產生出來,取而代之的是,您只需要付出乙個constructor(用以產生c)的代價。你無法做的比這更好了,因為c是乙個命名物件,而命名物件是不能被消除的。

結論:此特殊的優化行為有乙個專屬的名詞:return value optimization。利用函式的return點消除乙個區域性臨時物件(並可能利用函式呼叫端的某個物件取代),「擁有專屬名稱」說明它擁有很廣泛。

20 協助完成「返回值優化(RVO)」

19 最後曾提到了在函式通過傳值方式 by value 返回乙個物件時,不可避免地要生成乙個臨時物件,這會嚴重影響到程式的效率,如下例計算兩個分式的乘積 class crational int numer const get numerator int denom const get denomin...

協助完成返回值的優化

乙個返回物件的函式很難有較高的效率,因為傳值返回會導致呼叫物件內的構造和析構函式,這種呼叫是不能避免的。問題很簡單 乙個函式要麼為了保證正確的行為而返回物件要麼就不這麼做。如果它返回了物件,就沒有辦法擺脫被返回的物件。就說到這。考慮rational 有理數 類的成員函式operator class ...

返回值優化

通過傳值方式返回要建立新物件時,應注意使用的形式,例如在operator return integer left.l right.l 咋看起來這像是乙個 對乙個建構函式的呼叫 其實並非如此。這是臨時物件語法,它是在說 建立乙個臨時integer物件並返回它 據此我們可能認為如果建立乙個有名字的區域性...