C++中的右值引用
摘要
本文介紹C++中右值引用的含義、以及注意事項。
右值引用的含義
《C++ primer》第5版中說明了右值引用的含義:
所謂右值引用就是必須綁定到右值的引用
舉例來說:
int i = 42;
int &r = i; // 左值引用綁定到左值上
int &&rr = i; // 錯誤,右值引用不能綁定到左值上
int &&rri = i * 42; //正確,i*42是右值
此外,《C++ primer》中還說明了右值引用的重要性質:
只能綁定到一個將要銷毀的對象
需要注意的是,右值引用變量本身是左值,所以不能用一個右值引用變量初始化一個右值引用。
int &&rx = rri; //錯誤,rri是一個右值引用變量,是左值
那么,到底為什么說一個右值引用變量是一個左值呢?左右值的理解就是,
- 程序員可以取地址的是左值。
- 程序員不能取地址的是右值。
這里,rri
是一個變量,具有名字,可以取地址,所以說是左值。
左值引用和右值引用的區別
學了左值引用和右值引用,自然要問這兩個的區別是什么?左值引用和右值引用的區別就是初始化使用的規則不一樣,其余都一樣。
左值引用:只能使用左值進行初始化(除了,常量左值引用可以使用字面量初始化)
右值引用:只能使用右值初始化
在使用的時候,左值引用和右值引用無任何區別。
編譯器如何對待右值引用?
既然右值引用只能綁定到右值上,並且右值引用變量本身是左值,自然就有以下疑問:
問題1:右值引用綁定的是右值,而右值是將要消亡的,但是右值引用變量本身又是左值,左值就代表着是持久的。那么把編譯器是如何實現的?
問題2:按照我的這篇隨筆中的理解,我把右值理解成水,把引用理解成標簽,那么把一個右值引用(標簽)綁定到了右值(水)上,就說不通了,怎么解釋?
來看一下匯編代碼:

也就是說,當一個即將消亡的值被一個右值引用變量綁定時,編譯器會先把該值保存到棧上,然后把保存位置的內存地址賦值給右值引用。 從水桶和水的關系解釋,編譯器先創建了一個水桶,把水倒進水桶,並把標簽貼到該水桶上。這就是當一個右值引用綁定到右值時,編譯器的做法。
用法
當然,平時使用的話還是無需關心編譯器怎么處理的細節,只需要關心什么時候能用,什么時候不能用就行了。
什么時候不能用:
- 函數返回內部變量的右值引用:
比如:
int && test() {
int x = 1;
return x + 1; // 未定義行為,最好別用
}
什么時候能用:
右值引用主要的用途:
- 實現移動語義。
- 實現完美轉發。
總結
本文關鍵點:
- 右值引用只能綁定到右值上。
- 右值引用變量是左值。
- 右值引用變量指向的是一片內存,這片內存中存了值。所以,一個函數不能返回內部值的右值引用。
- 使用右值引用實現移動語義和完美轉發。