C++中的每一個表達式要麼是lvalue要麼是rvalue。lvalue表示一個內存位置,而rvalue表示計算表達式的結果。數組
rvalue引用是對有名稱變量的引用,並容許變量表示的內存經過lvalue引用來訪問。ide
rvalue引用是對包含表達式結果的內存位置的引用。函數
總之,表達式的結果和函數內定義的變量都屬於臨時變量,即rvalue。spa
int && num {2*x+3}; //rvalue引用表達式的臨時結果指針
int & num {x=5}; //lvalue引用code
常量引用:blog
void GetSet(int &num) { num += 1; }
Error (active) initial value of reference to non-const must be an lvalue.內存
void GetSet(const int &num) { num += 1; }
上面代碼:只看第一個函數頭GetSet(變量)是正確的,但GetSet(常量5)會被報錯,由於編譯器不容許對常量存在可能潛在的更改行爲。ci
規定常量做爲參數傳遞時需加const,即意味着不可更改。get
lvalue引用:
使用lvalue引用形參,能夠編寫直接訪問調用者實參的函數,避免了按值傳遞中的隱式複製。若不打算修改實參,則只須要給lvalue引用類型使用const修飾符,以免意外修改參數。
其實,不管是按值傳遞、按址傳遞參數或引用都是編譯器的規則,咱們須要熟悉參數在不一樣狀況下的傳遞,好的理解方式就是輸出地址來觀察。
void GetSet(int & num) { num += 1; } int main() { int v = 6; GetSet(v); cout << v<< endl; cin.get(); }
輸出結果: 7 ,num變量值經過引用改變了,能夠類比,變量的指針傳址方式。
rvalue引用:
void GetSet(int && num) { num += 1; } int main() { int v = 6; GetSet(v); cout << v<< endl; cin.get(); }
編譯器報錯:Error (active) an rvalue reference cannot be bound to an lvalue
可知lvalue不能經過rvalue引用,有rvalue引用形參的函數只能經過rvalue實參來調用。
void GetSet(int && num) { num += 1; cout <<"num="<< num << endl; } int main() { int v = 6; int c = 3; GetSet(v+c); cout <<"v="<< v <<" c="<< c <<endl; GetSet(5); cin.get(); }
上面代碼編譯經過,結果以下:
編譯器會爲表達式的結果生成一個臨時地址來存儲數值。而常量字面值 5 ,被當成一個表達式處理,而且存儲在函數引用形參的臨時位置。
輸出地址能夠看出,常量在rvalue引用的時候和表達式同樣處理了,即看作臨時變量。
函數返回值的引用:
int* GetSet(int num) { num += 1; int result {num}; return & result; } int main() { int v = 6; int *ptr=GetSet(v); cout <<"ptr="<< *ptr << endl; }
本段代碼能夠運行,但編譯器卻給出了以下警告:
「Warning C4172 returning address of local variable or temporary」
緣由在於:從函數中返回的引用是臨時變量的地址,應注意不要從函數中返回局部自動變量的地址。
能夠使用動態內存分配爲函數中的變量申請內存,因爲動態內存分配的內存是一直存在的(在堆中),除非用 delete 銷燬。即以下方式:
int* GetSet(int num) { num += 1; int *result{ new int {num} }; return result; } int main() { int v = 6; int *ptr=GetSet(v); cout <<"ptr="<< *ptr << endl;
delete ptr; }
觀察下面兩部分代碼的不一樣:
1、
double & lowest(double a[], int len) { int j{}; for (int i{ 1 }; i<len; i++) if (a[j]>a[i]) j = i; return a[j]; }
2、
double & lowest(double a[], int len) { int j{}; for (int i{ 1 }; i<len; i++) if (a[j]>a[i]) j = i; return & a[j]; }
引用是賦予存在變量的別名,因此實際返回的是數組元素a[j]的引用,而不是改元素包含的值。a[j]的地址用來初始化要返回的引用,該引用是編譯器建立的,由於返回類型是引用。
但返回a[j]和返回&a[j]是不一樣的。
返回&a[j],則指定的是a[j]地址,那是一個指針。因此,第二部分代碼會被報錯以下:
Error C2440 'return': cannot convert from 'double *' to 'double &'
由於指針和引用屬於不一樣類型。
Const 在傳參引用中的潛規則的:
double refcube(const double &ra) { return ra*ra*ra; } long edge = 5L; double side = 3.0; double c1 = refcube(edge); double c2 = refcube(7.0); double c3= refcube(side+10.0);
上面代碼中的函數調用都會產生臨時變量:
edge雖然是臨時變量,類型不正確,double引用不能指向long。
參數7.0和side+10.0類型雖然正確,但沒有名稱,編譯器將生成一個函數期間調用的匿名臨時變量。
而如今若是咱們去掉 const ,會發現編譯器會報錯:
Error:a reference of type "double &" (not const-qualified) cannot be initialized with a value of type "long"
Error:initial value of reference to non-const must be an lvalue
Why?
double refcube(double &ra) 是lvalue引用,要求使用知足類型的左值做爲參數。
那麼爲什麼 double refcube(double ra) 會經過編譯。
由於直接調用和使用const同樣編譯器會產生 臨時變量,只不過使用了 const 意味着不能修改參數。
固然此處代碼是能夠使用rvalue引用或const rvalue引用,但 Long 類型沒經過報錯以下:
Error:'double refcube(const double &&)': cannot convert argument 1 from 'long' to 'const double &&'