1. 程式人生 > 其它 >引用&行內函數

引用&行內函數

引用

  1. 概念
    引用是一個別名,不是新定義一個新變數。編譯器不會給引用變數重新分配空間,引用變數和其引用的實體共用同一份記憶體空間。
  2. 特性
    a.引用變數在定義時必須要初始化
    b.一個變數可以有多個引用
    c.引用變數一旦引用一個實體後,就不能再去引用其他的實體
  3. 三種傳參方式區別
    1.傳值
    優點:可以對外部的實參起到保護作用,不會因為對形參的改變而引起實參的修改
    缺點:a.不能通過形參改變外部的實參(因為形參是實參的一份拷貝,在函式體中修改形參實際修改的是實參的一份拷貝);b.傳參的效率低下
    2.傳地址
    優點:a.可以通過形參改變外部的實參;b.不需要對實參進行拷貝,傳參的效率高、節省空間
    缺點:a.在不需要通過形參改變外部實參的情況下,程式碼的安全性不高(但是可以使用const避免);b.每次再次使用的時候要進行判空,程式碼的可讀性不高
    3.傳引用
    優點:a.對形參進行修改可以達到對實參的改變;b.傳參效率高,節省空間;c.程式碼的可讀性高
    缺點:在不需要通過形參改變外部實參的情況下,程式碼的安全性不高(但是可以使用const避免);
    注意:如果需要通過形參改變外部的實參,可以優先使用引用
    如果不想要通過形參改變外部的實參:a如果是內建型別,直接傳值即可;b.如果是自定義型別,傳引用並且使用const對形參進行修飾
  4. 指標和引用的區別
    a.在底層的實現上:
    引用變數實際是有自己的空間的,該空間中放置的是其引用的實體地址;實現引用的技術是指標方式來實現的
    在這裡插入圖片描述說明:引用和指標在底層的實現方式上是相同的,引用就是按照指標的方式來實現的,從底層的實現上來看,是沒有任何區別的
    b.在概念和特性以及使用方式方面:
    1.引用概念上定義一個變數的別名,指標儲存的是一個變數地址;
    2.引用在定義時必須初始化,指標沒有要求;
    3.引用在初始化時引用一個實體後就不能再引用其他實體;而指標可以在任何時候指向任意一個同類型實體;
    4.沒有NULL引用,但有NULL指標;
    5.在sizeof中含義不同,引用結果為引用型別的大小,但指標始終是地址空間所佔位元組個數(32位平臺下佔4個位元組);
    6.引用自加即引用的實體增加1,指標自加即指標向後偏移一個型別的大小;
    7.有多級指標,但是沒有多級引用;
    8.訪問實體方式不同,指標需要顯式解引用,引用編譯器自己處理;
    9.引用比指標使用起來相對更安全;

行內函數

  1. 概念
    以inline修飾的函式叫做行內函數,編譯時C++編譯器會在呼叫行內函數的地方展開,沒有函式壓棧的開銷,行內函數提升程式執行的效率。
  2. 特性
    a.inline是一種以空間換時間的做法,省去呼叫函式額開銷。所以程式碼很長或者有迴圈/遞迴的函式不適宜使用作為行內函數。
    b.inline對於編譯器而言只是一個建議,編譯器會自動優化,如果定義為inline的函式體內有迴圈/遞迴等等,編譯器優化時會忽略掉內聯
    c.inline不建議宣告和定義分離,分離會導致連結錯誤。因為inline被展開,就沒有函式地址了,連結就會找不到。
  3. 巨集函式和行內函數的區別
    巨集函式的優點:
    在預處理階段,前處理器會將巨集函式使用巨集體展開,則少了函式呼叫引數壓棧、棧幀開闢等的開銷,提高了程式的效率,一般適合比較短小功能的程式碼。
    巨集函式的缺點:
    a.巨集函式在預處理階段展開,不會參與編譯,無參進行引數型別檢測,不安全
    b.巨集函式被展開了,不能除錯
    c.有時書寫比較麻煩,需要到處加括號,否則就會出錯
    d.可能會有副作用
    e.多次展開,可能會引起程式碼膨脹
#define MAX(A, B) (((A) > (B))? (A) : (B))
int main()
{
	 int a = 10, b = 20;
	 cout<<MAX(++b, a)<<endl; // 期望輸出21,但實際輸出的是22,因為直接替換後,++b算了兩次
	 return 0; 
 }

行內函數可以解決大部分巨集的缺陷,而且保留了巨集的優點,因此在C++中建議使用行內函數取代巨集函式。