const引用返回值


一、引用

引用是別名

必須在定義引用時進行初始化。初始化是指明引用指向哪個對象的唯一方法。

const 引用是指向 const 對象的引用:

const int ival = 1024;
const int &refVal = ival; // ok: both reference and object are const
int &ref2 = ival; // error: non const reference to a const object

 

可以讀取但不能修改 refVal ,因此,任何對 refVal 的賦值都是不合法的。這個限制有其意義:不能直接對 ival 賦值,因此不能通過使用 refVal 來修改ival。

同理,用 ival 初始化 ref2 也是不合法的:ref2 是普通的非 const 引用,因此可以用來修改 ref2 指向的對象的值。
通過 ref2 對 ival 賦值會導致修改const 對象的值。

為阻止這樣的修改,需要規定將普通的引用綁定到 const 對象是不合法的。

 

 

const 引用則可以綁定到不同但相關的類型的對象或綁定到右值。

int i = 42;

// legal for const references only
const int &r = 42;
const int &r2 = r + i;

i是int類型,r是const  int&類型 

 

非 const 引用只能綁定到與該引用同類型的對象。

如果非 const 引用綁定到與該引用不同類型的對象:

double dval = 3.14;
const int &ri = dval;

編譯器會把這些代碼轉換成如以下形式的編碼:

int temp = dval; // create temporary int from the double
const int &ri = temp; // bind ri to that temporary

如果 ri 不是 const,那么可以給 ri 賦一新值。這樣做不會修改 dval,
而是修改了 temp。


 

二、return

任何返回類型不是 void 的函數必須返回一個值,而且這個返回值的類型必須和函數的返回類型相同,或者能隱式轉化為函數的返回類型。也就是說重要的是定義函數時返回值類型不是return的。

 

1、返回非引用類型

函數的返回值用於初始化在調用函數處創建的臨時對象。在求解表達式時,如果需要一個地方儲存其運算結果,編譯器會創建一個沒有命名的對象,這就是臨時對象

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

int ret=max(1,8);
//該語句在編譯器內部:
temp =max(1,8);
ret=temp;

temp就是函數返回的創建的臨時對象,該對象對ret進行初始化

用函數返回值初始化臨時對象與用實參初始化形參的方法是一樣的。如果返回類型不是引用,在調用函數的地方會將函數返回值復制給臨時對象。當函數返回非引用類型時,其返回值既可以是局部對象,也可以是求解表達式的結果。

例如,下面的程序提供了一個計數器、一個單詞 word 和單詞結束字符串ending,當計數器的值大於 1 時,返回該單詞的復數版本:

// return plural version of word if ctr isn't 1
string make_plural(size_t ctr, const string &word,
const string &ending)
{
return (ctr == 1) ? word : word + ending;
}

我們可以使用這樣的函數來輸出單詞的單數或復數形式。這個函數要么返回其形參 word 的副本,要么返回一個未命名的臨時string 對象,這個臨時對象是由字符串 word 和 ending 的相加而產生的。這兩種情況下,return 都在調用該函數的地方復制了返回的 string 對象。


2、返回的引用

當函數返回引用類型時,沒有復制返回值。相反,返回的是對象本身

例如,考慮下面的函數,此函數返回兩個 string 類型形參中較短的那個字符串的引用:

const string &shorterString(const string &s1, const string &s2)
{
return s1.size() < s2.size() ? s1 : s2;
}

  

形參和返回類型都是指向 const string 對象的引用,調用函數和返回結果時,都沒有復制這些 string 對象。

 

 千萬不要返回局部對象的引用

千萬不要返回指向局部對象的指針

當函數執行完畢時,將釋放分配給局部對象的存儲空間。此時,對局部對象的引用就會指向不確定的內存。考慮下面的程序:

// Disaster: Function returns a reference to a local object
const string &manip(const string& s)
{
string ret = s;
// transform ret in some way
return ret; // Wrong: Returning reference to a local object!
}

這個函數會在運行時出錯,因為它返回了局部對象的引用。當函數執行完畢,字符串 ret 占用的儲存空間被釋放,函數返回值指向了對於這個程序來說不再有效的內存空間。

函數的返回類型可以是大多數類型。特別地,函數也可以返回指針類型。和返回局部對象的引用一樣,返回指向局部對象的指針也是錯誤的。

一旦函數結束,局部對象被釋放,返回的指針就變成了指向不再存在的對象的懸垂指針。

補充:

懸垂指針指向曾經存放對象的內存,指針指向的對象已經不再存在了,但該指針仍存在。懸垂指針往往導致程序錯誤,而且很難檢測出來。

一旦刪除了指針所指向的對象,立即將指針置為 0,這樣就非常清楚地表明指針不再指向任何對象了。

 

3、引用返回左值

char &get_val(string &str, string::size_type ix)
{
return str[ix];
}


int main() { string s("a value"); cout << s << endl; // prints a value get_val(s, 0) = 'A'; // changes s[0] to A cout << s << endl; // prints A value return 0; }

 

給函數返回值賦值可能讓人驚訝,由於函數返回的是一個引用,因此這是正確的,該引用是被返回元素的同義詞。
如果不希望引用返回值被修改,返回值應該聲明為 const:
const char &get_val(...

 

C++Primer4th第四版中文版

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM