問題描述
我知道內(nèi)聯(lián)是對編譯器的提示或請求,用于避免函數(shù)調(diào)用開銷.
那么根據(jù)什么可以確定一個函數(shù)是否適合內(nèi)聯(lián)呢?在哪種情況下應(yīng)該避免內(nèi)聯(lián)?
避免函數(shù)調(diào)用的成本只是故事的一半.
做:
- 使用
inline
而不是#define
- 非常小的函數(shù)非常適合
內(nèi)聯(lián)
:更快的代碼和更小的可執(zhí)行文件(更多機會留在代碼緩存中) - 這個函數(shù)很小并且經(jīng)常被調(diào)用
不要:
- 大型函數(shù):導(dǎo)致更大的可執(zhí)行文件,這會顯著影響性能,而不管調(diào)用開銷導(dǎo)致執(zhí)行速度更快
- I/O 綁定的內(nèi)聯(lián)函數(shù)
- 很少使用該函數(shù)
- 構(gòu)造函數(shù)和析構(gòu)函數(shù):即使為空,編譯器也會為它們生成代碼
- 在開發(fā)庫時破壞二進制兼容性:
- 內(nèi)聯(lián)現(xiàn)有函數(shù)
- 更改內(nèi)聯(lián)函數(shù)或使內(nèi)聯(lián)函數(shù)成為非內(nèi)聯(lián)函數(shù):庫的先前版本調(diào)用舊實現(xiàn)
在開發(fā)庫時,為了使類在未來可擴展,您應(yīng)該:
- 即使主體為空也添加非內(nèi)聯(lián)虛擬析構(gòu)函數(shù)
- 使所有構(gòu)造函數(shù)都非內(nèi)聯(lián)
- 編寫復(fù)制構(gòu)造函數(shù)和賦值運算符的非內(nèi)聯(lián)實現(xiàn),除非類不能按值復(fù)制
請記住,inline
關(guān)鍵字是對編譯器的一個提示:編譯器可能決定不內(nèi)聯(lián)函數(shù),并且可以決定內(nèi)聯(lián)未標(biāo)記為 inline
的函數(shù)首先.我通常避免標(biāo)記函數(shù) inline
(除了編寫非常非常小的函數(shù)時).
關(guān)于性能,明智的方法是(一如既往)分析應(yīng)用程序,然后最終內(nèi)聯(lián)
一組表示瓶頸的函數(shù).
參考文獻:
- 內(nèi)聯(lián)或不內(nèi)聯(lián)
- [9] 內(nèi)聯(lián)函數(shù)
- C++ 的政策/二進制兼容性問題
- GotW #33:內(nèi)聯(lián)
- 內(nèi)聯(lián) Redux
- 有效的 C++ - 第 33 條:明智地使用內(nèi)聯(lián)
Bjarne Stroustrup,C++ 編程語言:
<塊引用>一個函數(shù)可以被定義為inline
.例如:
inline int fac(int n){返回 (n <2) ?1 : n * fac(n-1);}
<塊引用>
inline
說明符提示編譯器它應(yīng)該嘗試為內(nèi)聯(lián)的 fac()
調(diào)用生成代碼,而不是為函數(shù)放置代碼一次然后通過通常的函數(shù)調(diào)用機制調(diào)用.聰明的編譯器可以為調(diào)用 fac(6)
生成常量 720
.內(nèi)聯(lián)函數(shù)相互遞歸的可能性,內(nèi)聯(lián)函數(shù)是否遞歸取決于輸入等,使得無法保證inline
函數(shù)的每次調(diào)用實際上都是內(nèi)聯(lián)的.編譯器的聰明程度無法被立法,因此一個編譯器可能生成720
,另一個6 * fac(5)
,還有另一個未內(nèi)聯(lián)調(diào)用fac(6)
.
為了在沒有異常聰明的編譯和鏈接工具的情況下使內(nèi)聯(lián)成為可能,內(nèi)聯(lián)函數(shù)的定義——而不僅僅是聲明——必須在范圍內(nèi)(第 9.2 節(jié)).inline
說明符不會影響函數(shù)的語義.特別是,內(nèi)聯(lián)函數(shù)仍然具有唯一地址,因此具有內(nèi)聯(lián)函數(shù)的 static
變量(第 7.1.2 節(jié)).
ISO-IEC 14882-1998,7.1.2 功能說明符
<塊引用>帶有 inline
說明符的函數(shù)聲明 (8.3.5, 9.3, 11.4) 聲明了一個內(nèi)聯(lián)函數(shù).內(nèi)聯(lián)說明符向?qū)崿F(xiàn)表明,在調(diào)用點對函數(shù)體進行內(nèi)聯(lián)替換優(yōu)于通常的函數(shù)調(diào)用機制.不需要實現(xiàn)在調(diào)用點執(zhí)行此內(nèi)聯(lián)替換;但是,即使省略了這種內(nèi)聯(lián)替換,7.1.2 中定義的內(nèi)聯(lián)函數(shù)的其他規(guī)則仍應(yīng)遵守.
I know that inline is a hint or request to compiler and its used to avoid function call overheads.
So on what basis one can determine whether a function is a candidate for inlining or not ? In which case one should avoid inlining ?
Avoiding the cost of a function call is only half the story.
do:
- use
inline
instead of#define
- very small functions are good candidates for
inline
: faster code and smaller executables (more chances to stay in the code cache) - the function is small and called very often
don't:
- large functions: leads to larger executables, which significantly impairs performance regardless of the faster execution that results from the calling overhead
- inline functions that are I/O bound
- the function is seldom used
- constructors and destructors: even when empty, the compiler generates code for them
- breaking binary compatibility when developing libraries:
- inline an existing function
- change an inline function or make an inline function non-inline: prior version of the library call the old implementation
when developing a library, in order to make a class extensible in the future you should:
- add non-inline virtual destructor even if the body is empty
- make all constructors non-inline
- write non-inline implementations of the copy constructor and assignment operator unless the class cannot be copied by value
Remember that the inline
keyword is a hint to the compiler: the compiler may decide not to inline a function and it can decide to inline functions that were not marked inline
in the first place. I generally avoid marking function inline
(apart maybe when writing very very small functions).
About performance, the wise approach is (as always) to profile the application, then eventually inline
a set of functions representing a bottleneck.
References:
- To Inline or Not To Inline
- [9] Inline functions
- Policies/Binary Compatibility Issues With C++
- GotW #33: Inline
- Inline Redux
- Effective C++ - Item 33: Use inlining judiciously
EDIT: Bjarne Stroustrup, The C++ Programming Language:
A function can be defined to be
inline
. For example:
inline int fac(int n)
{
return (n < 2) ? 1 : n * fac(n-1);
}
The
inline
specifier is a hint to the compiler that it should attempt to generate code for a call offac()
inline rather than laying down the code for the function once and then calling through the usual function call mechanism. A clever compiler can generate the constant720
for a callfac(6)
. The possibility of mutually recursive inline functions, inline functions that recurse or not depending on input, etc., makes it impossible to guarantee that every call of aninline
function is actually inlined. The degree of cleverness of a compiler cannot be legislated, so one compiler might generate720
, another6 * fac(5)
, and yet another an un-inlined callfac(6)
.To make inlining possible in the absence of unusually clever compilation and linking facilities, the definition–and not just the declaration–of an inline function must be in scope (§9.2). An
inline
especifier does not affect the semantics of a function. In particular, an inline function still has a unique address and so hasstatic
variables (§7.1.2) of an inline function.
EDIT2: ISO-IEC 14882-1998, 7.1.2 Function specifiers
A function declaration (8.3.5, 9.3, 11.4) with an
inline
specifier declares an inline function. The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions defined by 7.1.2 shall still be respected.
這篇關(guān)于什么時候使用內(nèi)聯(lián)函數(shù),什么時候不使用?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!