引用引數與引用返回值

2021-06-05 22:48:21 字數 3341 閱讀 2210

經常看到這樣的宣告:t& func(t& t),這種宣告和t func(t t)有什麼區別?書上的解釋是為

了提高效率,究竟是如何提高效率的呢?內部執行了什麼操作?本文通過8個小例子對引用引數

和引用返回進行了一次徹底的排查。

首先看一下在類的成員函式中的引用引數和引用返回值:

類定義class a

//建構函式

a(const a& other)//拷貝建構函式

~a(){}//析構函式

a& operator=(const a& other)//賦值函式

void func1(a a)

void func2(a& a)

a func3()

a& func4()};

這個類很簡單,只有乙個成員變數x,並且定義了預設建構函式、拷貝建構函式、析構函式和賦

值函式。為了能夠更清楚地看到哪個拷貝建構函式與賦值函式是否被呼叫,在這兩個函式中添

加了一些輸出資訊。

類中還定義了四個成員函式,下面分別分析這四個函式的執**況。

(1) 在main()函式中呼叫func1():

呼叫func1()int main()

func1()輸出結果copy

為什麼會有這樣的輸出結果呢?這是由於func1()中傳遞的是值引數,因此在執行函式體之前會

先產生乙個臨時物件,然後呼叫類的拷貝建構函式初始化這個臨時物件,從而輸出了"copy"。

在函式內部操作的是這個臨時物件,對臨時物件所做的任何修改不會反映到函式的實參上。

(2) 在main()函式中呼叫func2()以與func1()對比:

呼叫func2()int main()

func2()輸出結果

結果什麼也沒有輸出。

這是由於傳入的是乙個引用引數,因此在函式內部不需要產生乙個臨時物件來儲存物件資訊,

因此不會呼叫拷貝建構函式。這就是引用引數的作用,減少一次物件的拷貝,提高了函式的效率。

(3) 在main()函式中呼叫func3():

呼叫func3()int main()

func3()輸出結果

copy

assign

為什麼會輸出"copy"呢?這是因為函式採用的是值返回,因此為了儲存返回值,需要先建立一

個臨時物件,然後呼叫類的拷貝建構函式將*this的內容拷貝到這個臨時物件中,再將臨時物件

返回。最後通過賦值函式將該臨時物件的內容賦值給新物件。

(4) 在main()函式中呼叫func4()以與func3()對比:

呼叫func4()int main()

func4()輸出結果assign

只呼叫了賦值函式,這是引用函式採用的是引用返回,因此直接返回物件自身的引用*this,不

需要建立臨時物件來儲存物件資訊,因此不會呼叫拷貝建構函式。最後通過賦值函式直接將對

象本身的內容賦值給新物件。這就是引用返回值的作用,減少了一次物件的拷貝,提高了函式

的效率。

總結一下:在類的成員函式中,使用引用引數和引用返回值都不需要產生臨時物件,減少了一次物件的拷貝,提高了函式的效率。

那麼,如果將引數作為返回值返回,並且用引用接收返回值將會產生什麼效果呢?下面定義四

個全域性函式:

全域性函式a& func5(a& a)

a& func6(a a)

a func7(a& a)

a func8(a a)

(5) 在main()函式中呼叫func5():

呼叫func5()int main()

func5()輸出結果22

func5()採用了引用引數,並且以引用返回值的方式返回了該引數,因此a2是a1的乙個引用,對

a1的任何改變都會反映到a2上,所以a1、a2的成員變數x的值相同。

(6) 在main()函式中呼叫func6():

呼叫func6()int main()

編譯的時候會報乙個警告:

警告warning c4172: returning address of local variable or temporary

func6()輸出結果copy

24198610

警告的意思就是返回了乙個區域性變數的引用,這種用法實際上是錯誤的。區域性變數在函式返回

前就會被釋放,因此實際上a2引用到的一塊不可知的記憶體,這從輸出的a2.x的值"4198610"也可

以看出來。至於輸出"copy",是因為採用的是值引數,上面已經討論過,這裡不再贅述。

(7) 在main()函式中呼叫func7():

呼叫func7()int main()

func7()輸出結果copy21

這是一種比較特殊的用法,由於func7()採用的是值返回,因此在函式返回前將會產生乙個臨時

物件,並執行一次拷貝建構函式。這樣相當於a2引用了乙個臨時物件。前面曾經說過,臨時對

象將會在函式返回前被釋放,但是為什麼這裡輸出的結果是正常的呢?這是一種特殊情況,c++

規定,如果有臨時物件有乙個引用,那麼這個臨時物件的生存期將延長到和這個引用相同。

樣就可以解釋上面的輸出結果了:a2引用了乙個臨時物件,而不是引用了a1,因此a1的任何改

變不會影響到a2。

注意:在vc編譯環境下,const a& a2 = func7(a1);這行語句前面可以不加"const",但是在g++或者其他版本的編譯器中不加"const"將會產生編譯錯誤。加上"const"更加符合c++標準的規定,因為臨時物件不可見,不允許通過該引用來改變臨時物件的內容。

(8) 在main()函式中呼叫func8():

呼叫func8()int main()

func8()輸出結果copy

copy21

通過以上的分析,對這個輸出結果也就很好理解了:由於採用的是值引數,因此在函式體執行

前會呼叫一次拷貝建構函式;採用的是值返回值,因此在函式返回前又會呼叫一次拷貝構造函

數,這就是前兩個"copy"的由來。另外,a2引用的是乙個臨時物件,而不是引用了a1,因此a1

的任何改變不會影響到a2。

總結一下:

如果使用引用接收引用返回值,則返回的引用必須具有較長的生存期,不可以引用區域性變數。

如果使用引用接收值返回值,則引用了乙個臨時物件,該物件的生存期將延長到和這個引用相同。

引用引數,引用返回值

函式形參詩引用,程式輸出如程式最後的注釋,表明引用s代表的是物件s2.函式中的引用 includeusing namespace std class sample sample sample a x a.x int getx 形參為引用 void disp sample s void disp sa...

引用做引數與引用做返回值

一 引用做引數 引用做引數時,和c語言中的 傳址 是乙個道理,即通過函式來改變身處主函式中的變數。例 void fun int b int main 執行fun函式後,主函式中的整型變數a的值就變為了22,因為a和b實際上是同一處空間但是有了不同的名字。可以拓展到交換主函式中變數的值 void fu...

引用 引用型返回值

值形式的函式返回值通常都具有右值屬性,即在函式的呼叫者空間根據函式的返回型別建立乙個匿名物件,負責接收該函式的返回值 用於接收函式返回值的匿名物件和表示式的值類似,通常只具有語句級生命期且唯讀,即所謂將亡右值 如果函式返回的是乙個引用,那麼用於接收該返回值的就不再是乙個匿名的將亡右值物件,而是乙個引...