C++ 左值、右值、左值引用、右值引用 以及引用摺疊

非原創,由網上大神的答案拼湊而成。

左值與右值的定義:

      簡言之:變量是左值,可以出現在賦值語句的左邊;數字字面值是右值,不能出現在賦值語句左邊。

      詳細:左值可以出現在賦值語句的左邊或者右邊,即,左值也可以當右值用,右值只能出現在賦值的右邊,左值表示程序有特定的名字引用到這個值,右值表示程序中沒有特定的名字引用這個值。變量是左值,因此可以出現在賦值語句的左邊;數字字面值是右值,因此不能被賦值。實際上,左值是一個存儲地址,是一塊內存要存儲數據所要操作的地址;而右值是是一個具體的數據或者數值,也就是內存存儲的數據內容。

      int a=1;       //變量a是一個左值

      char str[]="hello world";     //數組成員str[i]是一個左值"hello world"是一個右值

      string("hello world");   是一個右值

左值引用於右值引用:

      左值引用:

              用法:Type & 左值引用名=左值表達式;

              例如:  int &a=b;

      右值引用:

              a 爲一個變量,我們無法建立 int &rb=a+1; 這樣的語法,因爲 a+1 此時是作爲一個右值來使用的, 我們無法把一個右值賦值給一個  

左值引用。(也就是左值引用相當於把一個變量的地址賦值給另外一個變量,這兩個變量可以訪問同一個內存,右值僅僅是一個數,而非內存中的某塊地址,因此無法把右值賦值給左值引用)。

               可用過下面語法實現:

                Type && 右值引用名=右值表達式;

                int &&rb=a+1;

參考:https://www.cnblogs.com/cly-blog/p/5980546.html

引用摺疊:

Class A { 
    A() 
    {// do something}
 }; 
 A GetA() 
 { 
    return A(); 
 } 
 int main() 
 { 
    A a1 = GetA(); // a1是左值 
    A&& a2 = GetA(); // a2是右值引用 
    return 0; 
 } 


          

a1是左值,在構造時使用了GetA() 產生的臨時對象,之後GetA()產生的臨時對象會銷燬。

a2是右值引用,其指向的就是GetA()所產生的對象,這個對象的聲明週期是和a2的聲明週期是一致的。即少了臨時對象,從而省去了臨時對象的構造和析構。

由此可見右值引用的好處,在新代碼中,右值引用是值得大力使用的。但是,在使用的時候,有例外情況了:T&&並不是一定表示右值,比如,如果它綁定的類型是未知的話,既可能是左值,又可能是右值。比如:

template<typename T>

void f(T&& param);

f(10); // 10是右值

int x = 10;

f(x); // x是左值

 

       以上這種未定的引用類型(param的類型)稱爲 universal references,這種類型必須被初始化,而它是左值還是右值則取決於它的初始化,如果被左值初始化,那麼它就是左值,反之亦然。那麼什麼時候是左值,什麼時候是右值,就需要進行類型推導才知道。

由於存在T&&這種未定的引用類型,當它作爲參數時,有可能被一個左值引用或右值引用的參數初始化,這是經過類型推導的T&&類型,相比右值引用(&&)會發生類型的變化,這種變化就稱爲引用摺疊。(《深入應用C++11-代碼優化與工程級應用》 --- 祁宇 P68

       

引用摺疊的規則如下(配合@jun-jun的答案)[和上一段的出處一樣]:
1.所有右值引用摺疊到右值引用上仍然是一個右值引用。(A&& && 變成 A&&)
2.所有的其他引用類型之間的摺疊都將變成左值引用。 (A& & 變成 A&; A& && 變成 A&; A&& & 變成 A&)

參考:https://www.zhihu.com/question/40346748



 



 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章