国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

C++ 關(guān)鍵字 inline詳細(xì)介紹

2020-01-26 15:37:47
字體:
供稿:網(wǎng)友

1.  內(nèi)聯(lián)函數(shù)

在C++中我們通常定義以下函數(shù)來求兩個整數(shù)的最大值:

復(fù)制代碼 代碼如下:

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ù)都要做很多工作:調(diào)用前要先保存寄存器,并在返回時恢復(fù),復(fù)制實(shí)參,程序還必須轉(zhuǎn)向一個新位置執(zhí)行

C++中支持內(nèi)聯(lián)函數(shù),其目的是為了提高函數(shù)的執(zhí)行效率,用關(guān)鍵字 inline 放在函數(shù)定義(注意是定義而非聲明,下文繼續(xù)講到)的前面即可將函數(shù)指定為內(nèi)聯(lián)函數(shù),內(nèi)聯(lián)函數(shù)通常就是將它在程序中的每個調(diào)用點(diǎn)上“內(nèi)聯(lián)地”展開,假設(shè)我們將 max 定義為內(nèi)聯(lián)函數(shù):

復(fù)制代碼 代碼如下:

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í)行開銷

2.  內(nèi)聯(lián)函數(shù)和宏

無論是《Effective C++》中的 “Prefer consts,enums,and inlines to #defines” 條款,還是《高質(zhì)量程序設(shè)計指南――C++/C語言》中的“用函數(shù)內(nèi)聯(lián)取代宏”,宏在C++中基本是被廢了,在書《高質(zhì)量程序設(shè)計指南――C++/C語言》中這樣解釋到:

3.  將內(nèi)聯(lián)函數(shù)放入頭文件

關(guān)鍵字 inline 必須與函數(shù)定義體放在一起才能使函數(shù)成為內(nèi)聯(lián),僅將 inline 放在函數(shù)聲明前面不起任何作用。

如下風(fēng)格的函數(shù) Foo 不能成為內(nèi)聯(lián)函數(shù):

復(fù)制代碼 代碼如下:

inline void Foo(int x, int y);   // inline 僅與函數(shù)聲明放在一起  
void Foo(int x, int y)
{
 ...
}

而如下風(fēng)格的函數(shù) Foo 則成為內(nèi)聯(lián)函數(shù):

復(fù)制代碼 代碼如下:

void Foo(int x, int y);  
inline void Foo(int x, int y)   // inline 與函數(shù)定義體放在一起
{
 ...
}

所以說,C++ inline函數(shù)是一種“用于實(shí)現(xiàn)的關(guān)鍵字”,而不是一種“用于聲明的關(guān)鍵字”。一般地,用戶可以閱讀函數(shù)的聲明,但是看不到函數(shù)的定義。盡管在大多數(shù)教科書中內(nèi)聯(lián)函數(shù)的聲明、定義體前面都加了 inline 關(guān)鍵字,但我認(rèn)為 inline 不應(yīng)該出現(xiàn)在函數(shù)的聲明中。這個細(xì)節(jié)雖然不會影響函數(shù)的功能,但是體現(xiàn)了高質(zhì)量C++/C 程序設(shè)計風(fēng)格的一個基本原則:聲明與定義不可混為一談,用戶沒有必要、也不應(yīng)該知道函數(shù)是否需要內(nèi)聯(lián)。

定義在類聲明之中的成員函數(shù)將自動地成為內(nèi)聯(lián)函數(shù),例如:

復(fù)制代碼 代碼如下:

class A

public:
 void Foo(int x, int y) { ... }   // 自動地成為內(nèi)聯(lián)函數(shù) 
}

但是編譯器是否將它真正內(nèi)聯(lián)則要看 Foo函數(shù)如何定義

內(nèi)聯(lián)函數(shù)應(yīng)該在頭文件中定義,這一點(diǎn)不同于其他函數(shù)。編譯器在調(diào)用點(diǎn)內(nèi)聯(lián)展開函數(shù)的代碼時,必須能夠找到 inline 函數(shù)的定義才能將調(diào)用函數(shù)替換為函數(shù)代碼,而對于在頭文件中僅有函數(shù)聲明是不夠的。

當(dāng)然內(nèi)聯(lián)函數(shù)定義也可以放在源文件中,但此時只有定義的那個源文件可以用它,而且必須為每個源文件拷貝一份定義(即每個源文件里的定義必須是完全相同的),當(dāng)然即使是放在頭文件中,也是對每個定義做一份拷貝,只不過是編譯器替你完成這種拷貝罷了。但相比于放在源文件中,放在頭文件中既能夠確保調(diào)用函數(shù)是定義是相同的,又能夠保證在調(diào)用點(diǎn)能夠找到函數(shù)定義從而完成內(nèi)聯(lián)(替換)。

但是你會很奇怪,重復(fù)定義那么多次,不會產(chǎn)生鏈接錯誤?

我們來看一個例子:

A.h :

復(fù)制代碼 代碼如下:

class A
{
public:
 A(int a, int b) : a(a),b(b){}
 int max();

private:
 int a;
 int b;
};

A.cpp :

復(fù)制代碼 代碼如下:

#include "A.h"

inline int A::max()
{
 return a > b ? a : b;
}

Main.cpp :

復(fù)制代碼 代碼如下:

#include <iostream>
#include "A.h"
using namespace std;

inline int A::max()
{
 return a > b ? a : b;
}

int main()
{
 A a(3, 5);
 cout<<a.max()<<endl;
 return 0;
}

一切正常編譯,輸出結(jié)果:5

 


倘若你在Main.cpp中沒有定義max內(nèi)聯(lián)函數(shù),那么會出現(xiàn)鏈接錯誤:

error LNK2001: unresolved external symbol "public: int __thiscall A::max(void)" (?max@A@@QAEHXZ)main.obj
找不到函數(shù)的定義,所以內(nèi)聯(lián)函數(shù)可以在程序中定義不止一次,只要 inline 函數(shù)的定義在某個源文件中只出現(xiàn)一次,而且在所有源文件中,其定義必須是完全相同的就可以。

在頭文件中加入或修改 inline 函數(shù)時,使用了該頭文件的所有源文件都必須重新編譯。

4.  慎用內(nèi)聯(lián)

內(nèi)聯(lián)雖有它的好處,但是也要慎用,以下摘自《高質(zhì)量程序設(shè)計指南――C++/C語言》:

而在Google C++編碼規(guī)范中則規(guī)定得更加明確和詳細(xì):

內(nèi)聯(lián)函數(shù):

Tip: 只有當(dāng)函數(shù)只有 10 行甚至更少時才將其定義為內(nèi)聯(lián)函數(shù).

定義: 當(dāng)函數(shù)被聲明為內(nèi)聯(lián)函數(shù)之后, 編譯器會將其內(nèi)聯(lián)展開, 而不是按通常的函數(shù)調(diào)用機(jī)制進(jìn)行調(diào)用.
優(yōu)點(diǎn): 當(dāng)函數(shù)體比較小的時候, 內(nèi)聯(lián)該函數(shù)可以令目標(biāo)代碼更加高效. 對于存取函數(shù)以及其它函數(shù)體比較短, 性能關(guān)鍵的函數(shù), 鼓勵使用內(nèi)聯(lián).
缺點(diǎn): 濫用內(nèi)聯(lián)將導(dǎo)致程序變慢. 內(nèi)聯(lián)可能使目標(biāo)代碼量或增或減, 這取決于內(nèi)聯(lián)函數(shù)的大小. 內(nèi)聯(lián)非常短小的存取函數(shù)通常會減少代碼大小, 但內(nèi)聯(lián)一個相當(dāng)大的函數(shù)將戲劇性的增加代碼大小. 現(xiàn)代處理器由于更好的利用了指令緩存, 小巧的代碼往往執(zhí)行更快。
結(jié)論: 一個較為合理的經(jīng)驗(yàn)準(zhǔn)則是, 不要內(nèi)聯(lián)超過 10 行的函數(shù). 謹(jǐn)慎對待析構(gòu)函數(shù), 析構(gòu)函數(shù)往往比其表面看起來要更長, 因?yàn)橛须[含的成員和基類析構(gòu)函數(shù)被調(diào)用!
另一個實(shí)用的經(jīng)驗(yàn)準(zhǔn)則: 內(nèi)聯(lián)那些包含循環(huán)或 switch 語句的函數(shù)常常是得不償失 (除非在大多數(shù)情況下, 這些循環(huán)或 switch 語句從不被執(zhí)行).
有些函數(shù)即使聲明為內(nèi)聯(lián)的也不一定會被編譯器內(nèi)聯(lián), 這點(diǎn)很重要; 比如虛函數(shù)和遞歸函數(shù)就不會被正常內(nèi)聯(lián). 通常, 遞歸函數(shù)不應(yīng)該聲明成內(nèi)聯(lián)函數(shù).(遞歸調(diào)用堆棧的展開并不像循環(huán)那么簡單, 比如遞歸層數(shù)在編譯時可能是未知的, 大多數(shù)編譯器都不支持內(nèi)聯(lián)遞歸函數(shù)). 虛函數(shù)內(nèi)聯(lián)的主要原因則是想把它的函數(shù)體放在類定義內(nèi), 為了圖個方便, 抑或是當(dāng)作文檔描述其行為, 比如精短的存取函數(shù).

-inl.h文件:


Tip: 復(fù)雜的內(nèi)聯(lián)函數(shù)的定義, 應(yīng)放在后綴名為 -inl.h 的頭文件中.


內(nèi)聯(lián)函數(shù)的定義必須放在頭文件中, 編譯器才能在調(diào)用點(diǎn)內(nèi)聯(lián)展開定義. 然而, 實(shí)現(xiàn)代碼理論上應(yīng)該放在 .cc 文件中, 我們不希望 .h 文件中有太多實(shí)現(xiàn)代碼, 除非在可讀性和性能上有明顯優(yōu)勢.

如果內(nèi)聯(lián)函數(shù)的定義比較短小, 邏輯比較簡單, 實(shí)現(xiàn)代碼放在 .h 文件里沒有任何問題. 比如, 存取函數(shù)的實(shí)現(xiàn)理所當(dāng)然都應(yīng)該放在類定義內(nèi). 出于編寫者和調(diào)用者的方便, 較復(fù)雜的內(nèi)聯(lián)函數(shù)也可以放到 .h 文件中, 如果你覺得這樣會使頭文件顯得笨重, 也可以把它萃取到單獨(dú)的 -inl.h 中. 這樣把實(shí)現(xiàn)和類定義分離開來, 當(dāng)需要時包含對應(yīng)的 -inl.h 即可。

本文參考書目:《C++ Primer》、《高質(zhì)量程序設(shè)計指南――C++/C語言》、Google C++編碼規(guī)范

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 平利县| 会泽县| 苏尼特右旗| 奉新县| 广汉市| 吉林市| 靖州| 上虞市| 景泰县| 新津县| 岚皋县| 万山特区| 佳木斯市| 吉安县| 岳池县| 建宁县| 巩义市| 永康市| 旅游| 封丘县| 邹城市| 伊吾县| 恩施市| 乐清市| 维西| 大余县| 绥滨县| 雅江县| 三原县| 麦盖提县| 包头市| 厦门市| 玉田县| 台中市| 紫阳县| 庆安县| 老河口市| 巫溪县| 苍梧县| 广河县| 峨眉山市|