條款30 透徹了解inlining的裡裡外外

2021-06-29 00:12:19 字數 1708 閱讀 3591

inline函式比巨集好用得多(tk2),編譯器通常被設計用來濃縮那些「不含函式呼叫」的**,所以編譯器有力能對inline函式執行語境相關最優化

但inline也有另一面,對函式呼叫都以函式本體替換之,會增加目標**的大小(object code)。在記憶體有限的環境中,造成的**膨脹會導致換頁行為,導致效率損失。換言之,如果inline函式本體很小,編譯器針對「函式本體」產生比「函式呼叫「更小**。

inline只是對編譯器的乙個申請而非強制命令,有明確提出和隱喻方式兩種。

隱喻方式是將函式定義於class中。如下**:

class  person

//隱喻的inline申請,定義於類中

...private:

inttheage;

};

明確宣告方式是在之前加inline關鍵字:

templateint line const t& std::max(const t& a,const t&b)  //關鍵字inline 明確申請

; //有意inline

void(*pf)()=f; //函式指標

...f(); //正常呼叫,inline

pf(); //函式指標呼叫,非inline

即使從不使用函式指標,也可能會遇到此類問題,如構造和析構函式,編譯器會生成其副本並獲得指標指向。

事實上構造和析構函式往往是inline的糟糕地方,如下**:

class base

;class derived:public base

//空的建構函式,事實上呢?

...private:

std::stringd1,d2,d3; //派生成員1-3

};

看上去inline非常好,因為不含任何**。但事實上不是。

當構造乙個物件時,其相應基類建構函式也被呼叫,反之析構也如此,如果構造過程中發生異常,該物件已構造的一部分會自動銷毀。

那個看起來為空的建構函式,相當於以下**:

derived::derived()   //空白建構函式的觀念性實現

//構造d1

cath(...)

trycath(...)

trycath(...)

}

雖然不是真正**,但已經反應出實際行為。我們可以知道「是否將derived建構函式inline」並非輕鬆。

同時inline函式不能隨著程式庫的公升級而公升級,換句話說,如果f是程式庫內的一inline函式,一旦改變f,則所有用到f的客戶端程式都必須重新編譯,反之,如果是non-line函式,就只要重新連線就好,遠比重新編譯負擔少。這就需要我們採取合適策略,一開始不應將任何函式宣告為inline,只限定於「一定為inline」或「平淡無奇的函式」,如上面的的person::age()。

8-2法則,乙個程式80%的時間用在20%的**上,作為開發者,我們的目標是有效增進整體效率的20%的**,然後獎它inline或盡可能**。

需要記住的:

1、將大多數inline限制在小型、頻繁呼叫的函式上,會使日後除錯和二進位制公升級更容易同時減少**膨脹和提高程式速度。

2、不要只因為函式template出現在標頭檔案就將其宣告為inline.

條款30 透徹了解inlining的裡裡外外

總結心得 1.首先inline只是對編譯器的乙個申請,不是強制命令,編譯器不是要強制執行你的這個inline,他根據實際情況接受或者拒絕。這個申請可以是隱式申請 比如定義在類內部的函式,或者定義在類內部的友元函式,會隱式申請為inline函式 顯示申請 在函式前面加inline 2.inline一般...

條款30 透徹了解inlining的裡裡外外

可能造成程式體積較大,即使擁有虛擬記憶體,inling的 膨脹也會導致額外的換頁行為,降低快取記憶體裝置的擊中率,以及伴隨而來的效率損失。總規則 inline只是對編譯器的乙個申請,不是強制命令。規則一 inline的兩種方式 隱喻方式,明確提出方式。隱喻方式,即在class宣告內定義函式,這樣的函...

30 透徹了解inlining 的裡裡外外

1 inline方法相當於文字替換,不需要承擔方法呼叫的額外開銷,同時還有潛在的優勢,文字替換後,編譯器會進行 優化。而對於方法呼叫,編譯器沒有能力進行 優化。2 顯而易見,inline方法往往會導致目標 膨脹變大。但是,對於方法本體很小的情況,可能會出現,替換後的文字比方法呼叫的 還要小。這也意味...