[原創(chuàng)文章歡迎轉(zhuǎn)載,但請保留作者信息] Justin 于 2010-01-04
使用內(nèi)聯(lián)函數(shù)(inline function)可以省去一般函數(shù)調(diào)用的入棧操作開銷,比宏(macro)要好用。從編譯器的角度來看,沒有函數(shù)調(diào)用的代碼要更容易優(yōu)化。 但是天下沒有免費的午餐,以空間換時間的內(nèi)聯(lián)函數(shù)同時也帶來了更大的程序占用空間,更甚者還會因為這變大的代碼空間導(dǎo)致額外的內(nèi)存換頁操作,降低指令緩存(instruction cache)的命中率……這些都是使用內(nèi)聯(lián)函數(shù)需要考慮到的負面影響。(Scott還是辯證地提醒了一點:當(dāng)內(nèi)聯(lián)函數(shù)非常短小時,相比一般意義上的函數(shù)調(diào)用,它能夠幫助編譯器生成更小的最終代碼和運行時更高的指令緩存命中率)
內(nèi)聯(lián)函數(shù)的聲明可以是顯式的:使用inline關(guān)鍵字;也可以是隱式的:在類的定義中定義函數(shù)。
內(nèi)聯(lián)函數(shù)一般而言都是定義在頭文件中,這是因為大多數(shù)編譯器的內(nèi)聯(lián)動作都是發(fā)生在編譯過程中。(也有著鏈接甚至是運行中才進行內(nèi)聯(lián)的,但是俺們這里隨大流,講主要矛盾) 雖然內(nèi)聯(lián)函數(shù)和函數(shù)模板有一點相似:它們都幾乎定義在頭文件中,但是這兩者之間沒有必然聯(lián)系,而非有的程序員想的那樣“函數(shù)模板一定是內(nèi)聯(lián)的”)
另外一點容易被初學(xué)者忽視的是,內(nèi)聯(lián)函數(shù)的定義僅僅是對編譯器提出內(nèi)聯(lián)的請求。編譯器完全有可能忽視這個請求,于是某“內(nèi)聯(lián)函數(shù)”有可能在最后還是生成了一般函數(shù)的代碼。在這個情況下編譯器很有可能是對的:
-
請求內(nèi)聯(lián)的函數(shù)有可能太過于復(fù)雜
-
請求內(nèi)聯(lián)的函數(shù)有可能是虛函數(shù)(虛函數(shù)的真正實體要在運行時才能得知,讓編譯器編譯階段去做內(nèi)聯(lián)實在有點強人所難)
-
請求內(nèi)聯(lián)的函數(shù)沒什么問題,但是在代碼中有用函數(shù)指針的方式調(diào)用該函數(shù)(這樣編譯器也沒辦法,如果不生成一般函數(shù)哪來的函數(shù)指針?)
這些情況下確實不應(yīng)該把函數(shù)作為內(nèi)聯(lián)函數(shù)。一個“內(nèi)聯(lián)函數(shù)”是否最終生成了內(nèi)聯(lián)函數(shù),還得編譯器說了算。 然而編譯器并不是總能幫助我們做出正確的決定,還有一些情況是需要我們自己做出判斷的:
-
請求內(nèi)聯(lián)的函數(shù)是構(gòu)造/析構(gòu)函數(shù)(表面上看起來某個構(gòu)造/析構(gòu)函數(shù)很短小甚至是空的,但是為了構(gòu)造/析構(gòu)類中的其他成員,編譯器有可能會“自覺”地寫入必要的代碼,這樣的構(gòu)造/析構(gòu)函數(shù)就有可能不適合再做內(nèi)聯(lián)了)這一點原文中有更詳細的說明。
-
當(dāng)編寫支持庫時(library)也不建議使用內(nèi)聯(lián)函數(shù),因為一旦用戶使用了這些含有內(nèi)聯(lián)函數(shù)的庫并編譯了自己的程序,這些內(nèi)聯(lián)函數(shù)就已經(jīng)“寫死”在他們的程序中了。當(dāng)日后對原先的庫做了更新修改,用戶就必須重新編譯整個程序才能用上新的補丁。而一般的函數(shù)就不會有這個問題:他們是動態(tài)鏈接的,用戶根本感覺不到任何改動。
-
考慮到很多調(diào)試器(debugger)無法調(diào)試內(nèi)聯(lián)函數(shù)(本來就沒有這么一個“函數(shù)”,叫人家怎么設(shè)斷點?),在調(diào)試版本中也不建議使用內(nèi)聯(lián)函數(shù)。
有那么多需要注意的地方,大師最后總結(jié)了一下:用好內(nèi)聯(lián)函數(shù)的第一步就是:不用內(nèi)聯(lián)函數(shù)。并沒有那么多的函數(shù)真正需要內(nèi)聯(lián),因為80%的程序運行時間都是花在了20%的代碼中。第二步是把內(nèi)聯(lián)函數(shù)當(dāng)成是手工優(yōu)化的手段,僅僅在非常需要效率和優(yōu)化的代碼中使用內(nèi)聯(lián)。
|