[讀書筆記][effective C++]條款30-inline的原理

張三思發表於2020-12-28

$KaTeX parse error: Expected '}', got 'EOF' at end of input: …00 程式碼難度: 程式碼量: $}

感受

在條款30裡, 作者告訴了我們幾點關於inline庫的知識. 我不會摘抄書裡的觀點, 我會說一下自己的看法, 所以如果你沒有看過之前書裡講的, 那麼讀這篇文章可能有點體驗不是很好, 所以有必要先說一下.

inline, 就是一種寫在程式碼裡, 能夠對編譯階段的進行優化的關鍵字, 或者說指令吧.

首先,我們知道,呼叫函式需要切換上下文,需要一個棧幀(一種記憶體中的資料結構)的開銷,所以呼叫函式是有成本的。在這個基礎上,我們再來理解 inline。
inline 的優化在於, 如果一個函式很短小(比如5行以內,很簡單的邏輯),沒必要專門開一個棧幀,那麼就乾脆用函式的方法體替換原來的函式呼叫好了。

我們之所以要把一個函式封裝, 是因為它重複出現,或者這塊邏輯影響閱讀, 等等。所以,封裝,是對寫程式的人友好的,但是對編譯器不友好, 對執行過程不友好。

為了執行效率,編譯器提出一個折衷的過程,如果這個函式很短,你就加一個 inline關鍵字,我在編譯的時候會直接使用方法體代替方法呼叫這行程式碼。
所以,我們搞懂了其背後邏輯之後,理解起來就很簡單了。我們可以認為, inline 就非常的像巨集裡面寫的函式,就是接近文字替換。
這是第一步我們需要搞懂的東西。

接下來, 我們再進一步討論一下 inline 關鍵字的特性。它實際執行涉及的東西會更多一點。

我們前面說了, inline 接近文字替換的東西, 所以 inline 的第一個特性,就是會引起編譯後的程式碼膨脹。 原來只有一個方法體,現在直接替換了方法呼叫, 那麼程式碼體積就會膨脹。

第二個, inline 是一個建議,程式設計師給編譯器的一個建議,而非一個命令。就像 Java 程式裡的 gc 相關命令。 具體的操作由編譯器來決定。當編譯器發現一個函式體其實很龐大的時候,或者很複雜的時候,inline 的好處不能覆蓋 inline 的成本的時候,編譯器會放棄 inline 操作。
書中舉了一個栗子, 是建構函式的例子, 往往我們會用初始化列表的方式或者直接賦值的方式來初始化一個物件。 但是其實背後要做很多事情,編譯器會幫我們生成很多輔助程式碼來完成物件的初始化, 所以一個建構函式看起來短小,其實實際上編譯器補全程式碼以後,體積非常的大,這個時候,就不適合使用 inline 操作了。

第三個特性, inline 函式要放在標頭檔案裡。
這個話有點懵逼,我來說一下自己的理解。 在有標頭檔案的專案裡, 一般也有原始碼檔案, 也就是分別有 .h 結尾的, 或者.hpp 結尾的, 也有 .cpp 結尾的, 我們一般會引入 .h 結尾的標頭檔案。 因為標頭檔案裡一般適合宣告,在編譯階段,是不會去主動尋找普通函式的函式程式碼的, 只有在連結的階段,才會根據函式體的宣告和呼叫去尋找函式的定義。
如果是普通的函式,那麼自然而然, 函式宣告和定義是可以分開的, 是可以出現在名稱不匹配的檔案裡的, 比如宣告出現在 a.h裡, 定義出現在 b.cpp 裡。但是 inline 函式是特殊的, 它要求使用的函式的時候,要用函式體去替換呼叫的那一行程式碼,所以要立刻馬上看到函式體的程式碼。 template,也就是模板也是類似的道理。
那麼,接下來,我問一個問題, inline 可以放在 .cpp 檔案裡嗎? 當然可以!!!
我們為什麼要把函式放在標頭檔案裡呢? 因為這個函式需要在這個原始碼檔案以外多處使用,所以我們必須把它放到標頭檔案裡。
可是如果這個函式只在一處使用,那麼我們直接把這個函式放在原始碼檔案(與標頭檔案相對的概念)裡就可以了。
例如:

int inline max_(int a, int b){
    return a>b?a:b;
}

int main(){
    int a = 10, b = a+ 1;
    cout << "a is " << a << ", and b is " << b << endl;
    cout << "the greater one is " << max_(a, b) << endl;
    return 0;
}

最後總結一下, 你可以認為 inline 就是函式版的文字替換。

參考

[1]KangRoger的 ec 讀書筆記
https://blog.csdn.net/kangroger/category_2771821.html
[2]《Effective C++》:條款30:透徹瞭解inlining的裡裡外外
https://blog.csdn.net/KangRoger/article/details/43909975

相關文章