C++中的inline用法

https://www.cnblogs.com/fnlingnzb-learner/p/6423917.html


1. 引入inline關鍵字的原因

在c/c++中,為了解決一些頻繁調用的小函數大量消耗棧空間(棧內存)的問題,特別的引入了inline修飾符,表示為內聯函數。

棧空間就是指放置程序的局部數據(也就是函數內數據)的內存空間。

在系統下,棧空間是有限的,假如頻繁大量的使用就會造成因棧空間不足而導致程序出錯的問題,如,函數的死循環遞歸調用的最終結果就是導致棧內存空間枯竭。

下面我們來看一個例子:

#include <stdio.h>
//函數定義為inline即:內聯函數
inline char* dbtest(int a) { return (i % 2 > 0) ? "奇" : "偶"; } int main() { int i = 0; for (i=1; i < 100; i++) { printf("i:%d 奇偶性:%s /n", i, dbtest(i)); } }

上面的例子就是標準的內聯函數的用法,使用inline修飾帶來的好處我們表面看不出來,其實,在內部的工作就是在每個for循環的內部任何調用dbtest(i)的地方都換成了(i%2>0)?”奇”:”偶”,這樣就避免了頻繁調用函數對棧內存重復開辟所帶來的消耗。

2. inline使用限制

inline的使用是有所限制的,inline只適合涵數體內代碼簡單的涵數使用,不能包含復雜的結構控制語句例如while、switch,并且不能內聯函數本身不能是直接遞歸函數(即,自己內部還調用自己的函數)。

3. inline僅是一個對編譯器的建議

inline函數僅僅是一個對編譯器的建議,所以最后能否真正內聯,看編譯器的意思,它如果認為函數不復雜,能在調用點展開,就會真正內聯,并不是說聲明了內聯就會內聯,聲明內聯只是一個建議而已。

4. 建議:inline函數的定義放在頭文件中

其次,因為內聯函數要在調用點展開,所以編譯器必須隨處可見內聯函數的定義,要不然就成了非內聯函數的調用了。所以,這要求每個調用了內聯函數的文件都出現了該內聯函數的定義

因此,將內聯函數的定義放在頭文件里實現是合適的,省卻你為每個文件實現一次的麻煩。

聲明跟定義要一致:如果在每個文件里都實現一次該內聯函數的話,那么,最好保證每個定義都是一樣的,否則,將會引起未定義的行為。如果不是每個文件里的定義都一樣,那么,編譯器展開的是哪一個,那要看具體的編譯器而定。所以,最好將內聯函數定義放在頭文件中。

5. 類中的成員函數與inline

定義在類中的成員函數缺省都是內聯的,如果在類定義時就在類內給出函數定義,那當然最好。如果在類中未給出成員函數定義,而又想內聯該函數的話,那在類外要加上inline,否則就認為不是內聯的。

例如,

class A
{public:void Foo(int x, int y) { } // 自動地成為內聯函數 }

將成員函數的定義體放在類聲明之中雖然能帶來書寫上的方便,但不是一種良好的編程風格,上例應該改成:

// 頭文件
class A
{public:void Foo(int x, int y); }

?

// 定義文件
inline void A::Foo(int x, int y){} 

?

6. inline 是一種“用于實現的關鍵字”

關鍵字inline 必須與函數定義體放在一起才能使函數成為內聯,僅將inline 放在函數聲明前面不起任何作用

如下風格的函數Foo 不能成為內聯函數:

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

?

而如下風格的函數Foo 則成為內聯函數:

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

?

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

7. 慎用inline

內聯能提高函數的執行效率,為什么不把所有的函數都定義成內聯函數?如果所有的函數都是內聯函數,還用得著“內聯”這個關鍵字嗎??
內聯是以代碼膨脹(復制)為代價,僅僅省去了函數調用的開銷,從而提高函數的執行效率。?
如果執行函數體內代碼的時間,相比于函數調用的開銷較大,那么效率的收獲會很少。另一方面,每一處內聯函數的調用都要復制代碼,將使程序的總代碼量增大,消耗更多的內存空間。

以下情況不宜使用內聯:?
(1)如果函數體內的代碼比較長,使用內聯將導致內存消耗代價較高。?
(2)如果函數體內出現循環,那么執行函數體內代碼的時間要比函數調用的開銷大。類的構造函數和析構函數容易讓人誤解成使用內聯更有效。要當心構造函數和析構函數可能會隱藏一些行為,如“偷偷地”執行了基類或成員對象的構造函數和析構函數。所以不要隨便地將構造函數和析構函數的定義體放在類聲明中。一個好的編譯器將會根據函數的定義體,自動地取消不值得的內聯(這進一步說明了 inline 不應該出現在函數的聲明中)。

8.總結

內聯函數并不是一個增強性能的靈丹妙藥。只有當函數非常短小的時候它才能得到我們想要的效果;但是,如果函數并不是很短而且在很多地方都被調用的話,那么將會使得可執行體的體積增大。?
最令人煩惱的還是當編譯器拒絕內聯的時候。在老的實現中,結果很不盡人意,雖然在新的實現中有很大的改善,但是仍然還是不那么完善的。一些編譯器能夠足夠的聰明來指出哪些函數可以內聯哪些不能,但是大多數編譯器就不那么聰明了,因此這就需要我們的經驗來判斷。如果內聯函數不能增強性能,就避免使用它!


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383943.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383943.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383943.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

UVa1262

算是一個模擬吧 #include<cstdio> #include<cstring> #include<algorithm> #include<climits> #include<cctype> #include<queue> #include<set> #include<vector>using namespace std;typedef long long ll; const int INF…

一個Linux下C線程池的實現

http://blog.csdn.net/zouxinfox/article/details/3560891 什么時候需要創建線程池呢&#xff1f;簡單的說&#xff0c;如果一個應用需要頻繁的創建和銷毀線程&#xff0c;而任務執行的時間又非常短&#xff0c;這樣線程創建和銷毀的帶來的開銷就不容忽視&#xff0c;這時也是線…

Gym100917 A - Abstract Picture

模擬賽的時候看這道題沒有什么頭緒&#xff0c;當時有點暈&#xff0c;感冒還沒有好&#xff0c;回來以后瞟了一眼題解就明白了&#xff0c;自己實現了一下&#xff0c;也沒有很復雜。大概的思路就像拓撲排序一樣&#xff0c;需要理解因為涂的是有順序的&#xff0c;所以我們總…

linux進程通信---幾個發送信號的函數(kill,raise,alarm,pause)

http://blog.csdn.net/zzyoucan/article/details/9235685 信號&#xff1a;信號是unix中最古老的進程通信的一種方式&#xff0c;他是軟件層次上對中斷機制的模擬&#xff0c;是一種異步通信方式&#xff0c;信號可以實現用戶空間進程和內核空間進程的交互&#xff0c;內核進程…

數據庫以及表的基本操作

一.數據庫的操作 create database[if not exists]數據庫名; 創建一個名字為company2的使用utf8忽略大小寫的數據庫 create database company charsetutf8 collate utf8_general_ci; 創建一個數據庫區分大小寫 create database company1 charsetutf8 collate utf8_general_bin;…

linux 網絡編程:使用兩線程實現socket同時收發數據

http://blog.csdn.net/li_wen01/article/details/52665505 工作中最近有使用到socket 向客戶端同時發送和接收數據&#xff0c;因為是嵌入式linux設備&#xff0c;且要求只能同時一個客戶端連接該端口。考慮到節省系統資源&#xff0c;只創建了兩個線程分別實現服務端的收發數據…

CF Gym102059 H. Fractions

題目要求找到給定區間的化簡后分子分母的和小于1000的數字的個數 我的想法是先找到所有的滿足要求的最簡分數(總數不超過1e6,而且遠小于),然后對詢問查找每個最簡分數出現的次數. #include<cstdio> #include<cstring> #include<algorithm> #include<cli…

C語言calloc()函數:分配內存空間并初始化

http://c.biancheng.net/cpp/html/134.html 頭文件&#xff1a;#include <stdlib.h> calloc() 函數用來動態地分配內存空間并初始化為 0&#xff0c;其原型為&#xff1a; void* calloc (size_t num, size_t size); calloc() 在內存中動態地分配 num 個長度為 siz…

CF Gym100917 C

要找到和為給定值的所有的等比數列. 1肯定是要特判一下. 我的想法是先找到所有等比為1的,等比為1就是將這個數分為相同的一些數,總共就是這個數的所有約數個數減一(有一個約數為1,題目要求至少分成兩個數). 對于其他的等比不為1 的,用等比數列的求和公式暴力一發就行了. #i…

多路轉接select1

高級IO 通常情況下所有的 IO 都可以分為兩步來完成, 第一步等待, 第二步數據搬遷, 為了提高 IO 效率通常所運用的方法就是減少等待的時間 舉個釣魚的例子 現在有五個人張三, 李四, 王五, 趙六, 錢七. 它們五個人來到湖邊來釣魚. 而它們五個人的釣魚方各不相同. 張三釣魚方法…

UVa11181

題目要求條件概率,用貝葉斯公式我們很容易得到我們需要求r個人買東西的概率和每個人買東西的條件下其他r-1個人買東西的概率.我們遞歸枚舉,每當枚舉到r個人買東西的時候,我們加入到r個人買東西的概率中(全概率公式),然后對于這r個人,除去自己買東西的概率就是其他r-1個人買東西…

Linux epoll模型

http://www.cnblogs.com/venow/archive/2012/11/30/2790031.html 定義&#xff1a; epoll是Linux內核為處理大批句柄而作改進的poll&#xff0c;是Linux下多路復用IO接口select/poll的增強版本&#xff0c;它能顯著的減少程序在大量并發連接中只有少量活躍的情況下的系統CPU利…

UVa11572

書上把這種問題叫做滑動窗口問題. 我的想法是先進行離散化,然后用一個數組記錄元素出現的位置,如果判斷某個元素已經出現,就將左端點移到上次出現的位置的后面.每次出現重復元素的時候判斷一下答案.我覺得這樣的復雜度是最低的. #include<cstdio> #include<cstring&…

Linux IO模式及 select、poll、epoll詳解

https://segmentfault.com/a/1190000003063859 同步IO和異步IO&#xff0c;阻塞IO和非阻塞IO分別是什么&#xff0c;到底有什么區別&#xff1f;不同的人在不同的上下文下給出的答案是不同的。所以先限定一下本文的上下文。 本文討論的背景是Linux環境下的network IO。一 概念…

mysql思維導圖

后期會不斷進行更新

CF Gym 101630 B Box

題目的意思大概就是給一個長方體的長寬高,問他能不能用一個w*h的紙剪出來,就是說展開圖的長寬能不能比給定的小. 題目給了11中展開圖的拓撲結構,我覺得這個很關鍵,要是題目沒有給這個我可能想不到那么全面,不過題目已經給了我就分析那11個圖形,發現展開圖的長寬大概分為三類 …

C++第一節課

C數據類型 幾個概念 命名空間是C標準庫引入的,其中命名空間可以解決變量沖突問題,當出現局部變量和全局變量同名的時候, 局部變量優先被訪問.同時命名空間的格式如同一下代碼 namespace name1 { int a 0; }namespace name2 { int a 2; } 注意C中的所有組件都是在一個叫做s…

【C/C++】關鍵字static

http://blog.csdn.net/woxiaohahaa/article/details/51014224 參考自&#xff1a;http://www.cnblogs.com/biyeymyhjob/archive/2012/07/19/2598815.html &#xff08;華山大師兄&#xff09; 這里我們只討論了C語言的static 首先我們回顧一下各種變量在內存中的位置&#xff1…

HDU5391威爾遜定理

威爾遜定理 當且僅當p為素數,p | (p-1)!1 若p為合數,則pa*b;如果a!b,那么p|(p-1)!, 如果ab,如果p為4,那么p|(p-1)!2,如果p大于4,那么sqrt和sqrt(2q)肯定屬于(p-1)!中,可以整除 #include<cstdio> #include<cstring> #include<algorithm> #include<climit…

C++的基本認識

簡單介紹C 語言特點 支持數據封裝和數據隱藏 在C中&#xff0c;類是支持數據封裝的工具&#xff0c;對象則是數據封裝的實現。C通過建立用戶定義類支持數據封裝和數據隱藏。 在面向對象的程序設計中&#xff0c;將數據和對該數據進行合法操作的函數封裝在一起作為一個類的定…