深入理解C++內(nèi)聯(lián)函數(shù)
內(nèi)聯(lián)函數(shù)的概念
以inline
修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時C++編譯器會在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開,沒有函數(shù)壓棧的開銷,內(nèi)聯(lián)函數(shù)的使用可以提升程序的運(yùn)行效率。
舉個例子:
在C++中我們通常定義以下函數(shù)來求兩個整數(shù)的最大值:
代碼如下:
int max(int a, int b) { return a > b ? a : b; }
為這么一個小的操作定義一個函數(shù)的好處有:
- 閱讀和理解函數(shù) max 的調(diào)用,要比讀一條等價的條件表達(dá)式并解釋它的含義要容易得多
- 如果需要做任何修改,修改函數(shù)要比找出并修改每一處等價表達(dá)式容易得多
- 使用函數(shù)可以確保統(tǒng)一的行為,每個測試都保證以相同的方式實(shí)現(xiàn)
- 函數(shù)可以重用,不必為其他應(yīng)用程序重寫代碼
雖然有這么多好處,但是寫成函數(shù)有一個潛在的缺點(diǎn):調(diào)用函數(shù)比求解等價表達(dá)式要慢得多。在大多數(shù)的機(jī)器上,調(diào)用函數(shù)都要做很多工作:
- 程序需要存儲當(dāng)前地址,以便調(diào)用結(jié)束后返回繼續(xù)執(zhí)行 - 程序?qū)魅牒瘮?shù)的參數(shù)壓棧 - 程序跳到跳到標(biāo)記函數(shù)起點(diǎn)的內(nèi)存單元,執(zhí)行函數(shù)代碼 - 函數(shù)調(diào)用結(jié)束后,將棧清空,返回到之前存儲的地址繼續(xù)執(zhí)行
C++中支持內(nèi)聯(lián)函數(shù)
,其目的是為了提高函數(shù)的執(zhí)行效率,用關(guān)鍵字 inline 放在函數(shù)定義(注意是定義而非聲明)的前面即可將函數(shù)指定為內(nèi)聯(lián)函數(shù),內(nèi)聯(lián)函數(shù)通常就是將它在程序中的每個調(diào)用點(diǎn)上“內(nèi)聯(lián)地”展開,相當(dāng)于直接copy一份函數(shù)體內(nèi)代碼,在執(zhí)行到的時候直接按照代碼順序執(zhí)行,省去了許多函數(shù)調(diào)用過程,節(jié)省了時間。
假設(shè)我們將 max 定義為內(nèi)聯(lián)函數(shù):
代碼如下:
inline int max(int a, int b) { return a > b ? a : b; }
則調(diào)用: cout<<max(a, b)<<endl; 在編譯時展開為: cout<<(a > b ? a : b)<<endl;
從而消除了把 max寫成函數(shù)的額外執(zhí)行開銷
是不是覺得這和宏有些像?那為什么不直接用宏?還要整個內(nèi)聯(lián)函數(shù)
內(nèi)聯(lián)函數(shù)和宏
首先,宏能夠表達(dá)的意思有限,通常是一行的表達(dá)式。其次,用宏的安全性不高,容易出錯。
假設(shè)定義宏如下:
#define MAX(a,b) a>b?:a:b
那么語句
res = MAX(i,j)+2;
會被預(yù)處理器擴(kuò)展為
res = i > j? i:j+2;
由于+的優(yōu)先級高于?,因此最終比較結(jié)果與我們期望不符。
那如果把宏修改為
#define MAX(a,b) (i > j? i:j)
仍然存在問題,例如
res = MAX(i++,j) res = (i++ < j? i++:j); // i被+了兩次
同時,宏無法調(diào)試,但內(nèi)聯(lián)函數(shù)可以。在程序的調(diào)試版本,內(nèi)聯(lián)函數(shù)并沒有真正內(nèi)聯(lián),就像普通函數(shù)一樣實(shí)現(xiàn)調(diào)試,在程序的發(fā)行版本,編譯器才會實(shí)現(xiàn)真正內(nèi)聯(lián)。
無論是《Effective C++》中的 “Prefer consts,enums,and inlines to #defines” 條款,還是《高質(zhì)量程序設(shè)計指南——C++/C語言》中的“用函數(shù)內(nèi)聯(lián)取代宏”,宏在C++中基本是被廢了。
內(nèi)聯(lián)函數(shù)的特性
1、inline是一種以空間換時間的做法,省了去調(diào)用函數(shù)的額外開銷。由于內(nèi)聯(lián)函數(shù)會在調(diào)用的位置展開,所以代碼很長或者有遞歸的函數(shù)不適宜作為內(nèi)聯(lián)函數(shù)。頻繁調(diào)用的小函數(shù)建議定義成內(nèi)聯(lián)函數(shù)。
2、inline對于編譯器而言只是一個建議,編譯器會自動優(yōu)化,如果定義為inline的函數(shù)體內(nèi)有遞歸等,編譯器優(yōu)化時會忽略掉內(nèi)聯(lián)。
3、inline不建議聲明和定義分離
,分離會導(dǎo)致鏈接錯誤。因?yàn)閕nline被展開,就沒有函數(shù)地址了鏈接就會找不到。
4、關(guān)鍵字 inline 必須與函數(shù)定義體放在一起才能使函數(shù)成為內(nèi)聯(lián),僅將 inline 放在函數(shù)聲明前面不起任何作用。
5 .相比于宏,有類型檢查,安全性更高,具有一般函數(shù)特性,可調(diào)試。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C++ 中dynamic_cast<>的使用方法小結(jié)
將一個基類對象指針(或引用)cast到繼承類指針,dynamic_cast會根據(jù)基類指針是否真正指向繼承類指針來做相應(yīng)處理2013-03-03Linux環(huán)境下段錯誤的產(chǎn)生原因及調(diào)試方法小結(jié)
借此機(jī)會系統(tǒng)學(xué)習(xí)了一下,這里對Linux環(huán)境下的段錯誤做個小結(jié),方便以后同類問題的排查與解決2011-11-11