Effective C++ 第三十條 Understand the ins and outs of inlining.

透徹了解 inlining 的里里外外
inline 的優(yōu)點(diǎn)
Inline 函數(shù)是非常好的設(shè)計(jì),既可以調(diào)用它們又可以不需要承受函數(shù)調(diào)用而導(dǎo)致的額外開銷(如寄存器保存等)。編譯器的優(yōu)化機(jī)制通常就是濃縮“不含函數(shù)調(diào)用”的代碼。但是 inline 也有副作用,就是增加目標(biāo)代碼的大小,具體如何請(qǐng)看下方實(shí)例:
如果 inline 函數(shù)有多條(也不能太多,太多的話編譯器不會(huì)把其當(dāng)作 inline 函數(shù)),代碼就膨脹得很快。如果代碼膨脹而造成程序體積過(guò)大,inline 會(huì)導(dǎo)致額外的內(nèi)存換頁(yè)(paging),降低指令還俗緩存裝置的命中率(instruction cache hit rate)。
inline 的提出有兩種,一種是隱式,一種是顯式。隱式提出就是將函數(shù)定義在 class 內(nèi):
另一種是顯式,如 case 1 中那樣,函數(shù)用 inline 修飾。
但是要注意一點(diǎn),inline 只是一種申請(qǐng),并不是強(qiáng)制編譯器要這么做,編譯器可以不聽。
inline 的缺點(diǎn)
Inline 函數(shù)通常被置于頭文件內(nèi),因?yàn)榇蠖鄶?shù)環(huán)境下進(jìn)行編譯,為了將函數(shù)調(diào)用替換為被調(diào)用函數(shù)的本體,是需要知道這個(gè)函數(shù)長(zhǎng)什么樣子的,否則無(wú)法完成替換。少數(shù)環(huán)境可以在運(yùn)行期再進(jìn)行替換,但是畢竟是少數(shù)。這就導(dǎo)致了大多數(shù)情況下,如果 inline 的函數(shù)本體有修改,所有涉及到該 inline 函數(shù)的整個(gè)文件需要重新編譯,你應(yīng)該聽說(shuō)過(guò) C++ 大項(xiàng)目編譯一次時(shí)間很長(zhǎng)。
inline 函數(shù)無(wú)法設(shè)置斷點(diǎn),因?yàn)檫@個(gè)函數(shù)在執(zhí)行過(guò)程中早就被替換為了函數(shù)本體,這個(gè)函數(shù)是不存在的,也就無(wú)法根據(jù)這個(gè)函數(shù)來(lái)設(shè)置斷點(diǎn)。如果需要調(diào)試,只能在調(diào)試版程序中禁止發(fā)生 inlining。
inline 的注意點(diǎn)
inline 很多時(shí)候要和 template 一起使用,只有 template 下所有類型都需要被聲明為 inline 才使用 inline ,否則就不該使用 inline。大部分編譯器拒絕太過(guò)復(fù)雜的 inlining(比如帶有循環(huán)和遞歸)。而且?guī)缀跛袑?duì) virtual 函數(shù)的調(diào)用都會(huì)使得 inlining 落空。
即使編譯器有意 inlining 某個(gè)函數(shù),實(shí)際上還是需要為其生成一個(gè)函數(shù)本體,因?yàn)槲覀兛赡軙?huì)在代碼中使用到函數(shù)指針,如果沒有這個(gè)函數(shù)本體,指向該函數(shù)的函數(shù)指針將為空,這不合理。