0 左值和右值
一個左值表達式代表的是對象本身,而右值表達式代表的是對象的值;變量也是左值。
1 右值引用作用
為了支持移動操作(包括移動構造函數和移動賦值函數),C++才引入了一種新的引用類型——右值引用,可以自由接管右值引用的對象內容。
2 右值引用綁定的對象
返回非引用類型的函數,產生右值的表達式(算術表達式、關系表達式、位、后置遞增遞減)
3 和左值引用的區別
- 綁定的對象(引用的對象)不同,左值引用綁定的是返回左值引用的函數、賦值、下標、解引用、前置遞增遞減
- 左值持久,右值短暫,右值只能綁定到臨時對象,所引用的對象將要銷毀或該對象沒有其他用戶
- 使用右值引用的代碼可以自由的接管所引用對象的內容
清單1
1 int &&i = 1; 2 int b = 2; 3 cout << i << endl; 4 i = b; 5 cout << i << endl; 6 //輸出1 2
清單1中i綁定到了右值1,說明:初始化時,右值引用一定要用一個右值表達式綁定;初始化之后,可以用左值表達式修改右值引用的所引用臨時對象的值
清單2:清單1反匯編
;省略上面代碼 int &&i = 1; 00C044DE mov dword ptr [ebp-14h],1 00C044E5 lea eax,[ebp-14h] 00C044E8 mov dword ptr [ebp-8],eax int b = 2; 00C044EB mov dword ptr [ebp-20h],2 ;省略輸出代碼 i = b; 00C04523 mov eax,dword ptr [ebp-8] 00C04526 mov ecx,dword ptr [ebp-20h] 00C04529 mov dword ptr [eax],ecx ;省略余下代碼
清單2可以清楚看出右值引用的底層實現。第3行對一個臨時變量賦值0,第4-5行將臨時變量地址存儲至i中,因此i存儲的實際是臨時對象的地址(也就是對臨時對象的一種引用)。
第10行mov eax,dword ptr [ebp-8]取出了i存儲的數據(臨時對象地址),11-12行將b變量的值賦值到臨時對象,而i存儲的數據不變,仍是存儲臨時對象的地址(也就是對臨時對象的一種引用)。
清單3:右值引用變量也是左值
1 int&&temp =0; 2 int&&i = temp;
清單3中temp是一個右值引用變量,變量是左值,因此i引用temp左值是非法的!
清單4:右值引用賦值右值引用
1 int &&temp = 0; 2 int &&i = 1; 3 i = temp;
清單4是合法的,取出temp所引用臨時對象的值,再賦值給i所引用臨時對象的值。
清單5
1 class A{ 2 public: 3 int b; 4 int a; 5 char c[256]; 6 }; 7 void f(A a) 8 { 9 ; 10 } 11 int main(int argc, char const *argv[]) 12 { 13 A &&a = A(); 14 f(a); 15 }
清單5是合法的,過程符合一般邏輯,即會生成a引用臨時對象的一個副本,再傳入副本對象的地址。如果f函數的形參是引用類型的,那么調用f函數傳入的是a引用對象的地址,而不會生成副本
4 總結
- 右值引用,是對臨時對象的一種引用,它是在初始化時完成引用的,但是右值引用不代表引用臨時對象后就不能改變右值引用所引用對象的值,仍然可以在初始化后改變臨時對象的值。
- 對於引用類型,可以用於它所引用對象類型的可以用的地方(把它當成普通變量),只不過用到的值是它所引用的對象的值,它還可以用於移動構造或賦值函數的地方。
本文鏈接:【原創】深入理解c++的右值引用 http://www.cnblogs.com/cposture/p/4927712.html