Guru of the Week 條款27:轉呼叫函式 (轉)
GotW#27 轉呼叫(Forwarding Functions):namespace prefix = o ns = "urn:schemas--com::office" />
難度:3 / 10
怎樣將轉呼叫函式寫得最好?原本答案很簡單,但我們已經知道C++語言近來發生了微妙的變化。
問題
轉呼叫函式對於將任務傳遞給其它函式或時很有用,尤其當它們被設計得很高效時。
評論一下下面這個轉呼叫函式。你試圖修改它嗎?如果是的話,怎麼來?
// file f.cpp
#include "f.h"
/*...*/
bool f( X x ) {
return g( x );
}
(說明:本次GotW的目的之一是闡明在July [1997]於London加入到C++語言中的一個微妙改進所造成的後果。)
解答
轉呼叫函式對於將任務傳遞給其它函式或物件時很有用,尤其當它們被設計得很高效時。
關鍵點是:。
評論一下下面這個轉呼叫函式。你試圖修改它嗎?如果是的話,怎麼來?
// file f.cpp
#include "f.h"
/*...*/
bool f( X x ) {
return g( x );
}
有兩個主要改進可使得這個函式更高效。第一個應該總被採用,第二個需要權衡。
1.傳參時使用傳const的引用代替傳值
“這不會造成混亂嗎?”你可能會問。不,它不會,至少在這種情況下。直到最近,C++語言才規定:因為可以確保引數x除了被傳遞給g()外沒有被其它地方使用,編譯器可以將x完全掉。例如,這樣的程式碼:
X my_x;
f( my_x );
編譯器可以:
a)產生一個my_x的複製供f()使用(就是f()的程式碼體中的形參x),然後將這個複製傳給g();或者
b)直接將my_x傳給g()而不生成複製,因為它注意到這個額外的複製除了作g()的引數外根本沒被使用。
後者更高效,不是嗎?這是編譯器試圖作的最佳化,不是嗎?
是的,是的,但只到July 1997的London會議。在那次會議上,“限制編譯器作這種取消額外複製的最佳化”的提案得到了更多的支援。〖注1〗編譯器唯一可以取消額外複製構造的地方是“返回值最佳化”(在你的C++寶典中查詢細節吧)和“臨時物件”。
這意味著,象f這樣的轉呼叫函式,編譯器被要求產生兩份複製。既然我們(作為f的作者)知道這個額外的複製不是必須的,我們應該按照通常的辦法將x申明為const X&型的引數。
(注意:如果我們一直就是這麼做的,而不是依賴於知道編譯器被允許做些什麼,那麼,這個規則的變化不會對我們造成任何影響。這就是一個“簡單就是美”例子--儘可能避開語言的細枝末節,別耍小聰明。)
2.函式內聯
這個需要權衡。要之,預設將所有函式都實現為外聯,有選擇地將確實需要內聯以提高效率的函式實現為內聯。
當你將函式內聯時,積極面是你避免了對f函式的的額外開銷。
消極面是內聯f暴露了f的實現,並使得的程式碼依賴於此實現,當f被改變時,所有的使用者程式碼都必須被重編譯。更嚴重的是,使用者程式碼現在至少需要知道函式g()的原型,這有點噁心,因為使用者根本沒有直接呼叫函式g,原本可以根本不需要知道它的原型的(至少,從我們的例子上,是這樣的)。於是,如果g()自己發生了變化,接受其它型別的其它引數時,使用者的程式碼將變得也需要知道這些型別的申明。
內聯和非內聯都可以。必須在優缺點間進行權衡,取決於f現在是怎樣被使用的以及使用的廣泛程度,和將來可能變為怎樣被使用的以及使用的廣泛程度。
GotW給出的程式碼規範:
l 傳參時,用傳const的引用來代替傳值
l 避免函式內聯,除非profiler告訴你有這個必要(員在猜測效能瓶頸點方面是很不準的)
注1:這個改進是必要的,它避免了編譯器未經允許地省略複製構造時帶來問題,尤其當複製構造有副作用時。很多時候,程式碼需要計算物件的複製數目。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992727/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Guru of the Week 條款05:覆寫虛擬函式 (轉)函式
- Guru of the Week 條款19:自動轉換 (轉)
- Guru of the Week 條款28:“Fast Pimpl”技術 (轉)AST
- Guru of the Week 條款09:記憶體管理(上篇) (轉)記憶體
- Guru of the Week 條款10:記憶體管理(下篇) (轉)記憶體
- Guru of the Week 條款24:編譯級防火牆 (轉)編譯防火牆
- Guru of the Week 條款30附錄:介面原則 (轉)
- Guru of the Week 條款13:物件導向程式設計 (轉)物件程式設計
- Guru of the Week 條款07:編譯期的依賴性 (轉)編譯
- Guru of the Week 條款11:物件等同(Object Identity)問題 (轉)物件ObjectIDE
- Guru of the Week 條款14:類之間的關係(上篇) (轉)
- Guru of the Week 條款15:類之間的關係(下篇) (轉)
- Guru of the Week #5:虛擬函式的重新定義 (轉)函式
- Guru of the Week 條款16:具有最大可複用性的通用Containers (轉)AI
- C++ articles:Guru of the Week #1 (轉)C++
- Guru of the week:#18 迭代指標. (轉)指標
- Guru of the Week 條款08:GotW挑戰篇——異常處理的安全性 (轉)Go
- Guru of the Week 條款23:物件的生存期(第二部分) (轉)物件
- Guru of the week:#19 自動型別轉換. (轉)型別
- Guru of the Week 條款22:物件的生存期(第一部分) (轉)物件
- Guru of the Week 條款21:程式碼的複雜性(第二部分) (轉)
- Guru of the week:#17 型別對映. (轉)型別
- Guru of the Week 條款20:程式碼的複雜性(第一部分) (轉)
- C++ articles:Guru of the Week #4 -- Class Mechantics (轉)C++
- Guru of The week #20 程式碼的複雜性 Ⅰ. (轉)
- More Effective C++ 條款27(下) (轉)C++
- C++ articles:Guru of the Week #3:使用標準庫 (轉)C++
- [轉載]論函式呼叫約定函式
- C語言中庫函式呼叫幾例(轉)C語言函式
- 呼叫API函式設計ABOUT視窗 (轉)API函式
- VB動態呼叫外部函式的方法 (轉)函式
- 呼叫類庫函式的簡單加密(轉的)函式加密
- 呼叫建構函式進行型別轉換函式型別
- 走近VB.Net(二) 再談函式呼叫 (轉)函式
- 條款14 基類的解構函式一定要定義為虛擬函式(From Effective C++) (轉)函式C++
- Visual C++中函式呼叫方式淺探 (轉)C++函式
- 透過例子學習Lua(4)--函式的呼叫(轉)函式
- ASP中函式呼叫對引數的影響 (轉)函式