問題描述
我知道內聯是對編譯器的提示或請求,用于避免函數調用開銷.
那么根據什么可以確定一個函數是否適合內聯呢?在哪種情況下應該避免內聯?
避免函數調用的成本只是故事的一半.
做:
- 使用
inline
而不是#define
- 非常小的函數非常適合
內聯
:更快的代碼和更小的可執行文件(更多機會留在代碼緩存中) - 這個函數很小并且經常被調用
不要:
- 大型函數:導致更大的可執行文件,這會顯著影響性能,而不管調用開銷導致執行速度更快
- I/O 綁定的內聯函數
- 很少使用該函數
- 構造函數和析構函數:即使為空,編譯器也會為它們生成代碼
- 在開發庫時破壞二進制兼容性:
- 內聯現有函數
- 更改內聯函數或使內聯函數成為非內聯函數:庫的先前版本調用舊實現
在開發庫時,為了使類在未來可擴展,您應該:
- 即使主體為空也添加非內聯虛擬析構函數
- 使所有構造函數都非內聯
- 編寫復制構造函數和賦值運算符的非內聯實現,除非類不能按值復制
請記住,inline
關鍵字是對編譯器的一個提示:編譯器可能決定不內聯函數,并且可以決定內聯未標記為 inline
的函數首先.我通常避免標記函數 inline
(除了編寫非常非常小的函數時).
關于性能,明智的方法是(一如既往)分析應用程序,然后最終內聯
一組表示瓶頸的函數.
參考文獻:
- 內聯或不內聯
- [9] 內聯函數
- C++ 的政策/二進制兼容性問題
- GotW #33:內聯
- 內聯 Redux
- 有效的 C++ - 第 33 條:明智地使用內聯
Bjarne Stroustrup,C++ 編程語言:
<塊引用>一個函數可以被定義為inline
.例如:
inline int fac(int n){返回 (n <2) ?1 : n * fac(n-1);}
<塊引用>
inline
說明符提示編譯器它應該嘗試為內聯的 fac()
調用生成代碼,而不是為函數放置代碼一次然后通過通常的函數調用機制調用.聰明的編譯器可以為調用 fac(6)
生成常量 720
.內聯函數相互遞歸的可能性,內聯函數是否遞歸取決于輸入等,使得無法保證inline
函數的每次調用實際上都是內聯的.編譯器的聰明程度無法被立法,因此一個編譯器可能生成720
,另一個6 * fac(5)
,還有另一個未內聯調用fac(6)
.
為了在沒有異常聰明的編譯和鏈接工具的情況下使內聯成為可能,內聯函數的定義——而不僅僅是聲明——必須在范圍內(第 9.2 節).inline
說明符不會影響函數的語義.特別是,內聯函數仍然具有唯一地址,因此具有內聯函數的 static
變量(第 7.1.2 節).
ISO-IEC 14882-1998,7.1.2 功能說明符
<塊引用>帶有 inline
說明符的函數聲明 (8.3.5, 9.3, 11.4) 聲明了一個內聯函數.內聯說明符向實現表明,在調用點對函數體進行內聯替換優于通常的函數調用機制.不需要實現在調用點執行此內聯替換;但是,即使省略了這種內聯替換,7.1.2 中定義的內聯函數的其他規則仍應遵守.
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.
這篇關于什么時候使用內聯函數,什么時候不使用?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!