一般而言,一個左值表示式表示的是一個物件的身份,而一個右值表示式表示的是物件的值。
我們不能將其繫結到要求轉換的表示式、字面常量或是返回右值的表示式(參見 2.3.1節,第 46頁)。右值引用有著完全相反的繫結特性:我們可以將一個右值引用繫結到這類表示式上,但不能將一個右值引用直接繫結到一個左值上:
int i = 42;
int &r = i; //正確:r引用i
int &&rr = i; //錯誤:不能將一個右值引用繫結到一個左值上
int &r2 = i* 42; //錯誤:i*42是一個右值
const int &r3 = i*42; //正確:我們可以將一個const的引用繫結到一個右值上
int &&rr2 = i * 42; //正確:將rr2 繫結到乘法結果上
返回左值引用的函式,連同賦值、下標、解引用和前置遞增/遞減運算子,都是返回左值的表示式的例子。我們可以將一個左值引用繫結到這類表示式的結果上。
返回非引用型別的函式,連同算術、關係、位以及後置遞增/遞減運算子,都生成右值。我們不能將一個左值引用繫結到這類表示式上,但我們可以將一個 const 的左值引用或者一個右值引用繫結到這類表示式上。
左值持久;右值短暫
考察左值和右值表示式的列表,兩者相互區別之處就很明顯了:左值有持久的狀態而右值要麼是字面常量,要麼是在表示式求值過程中建立的臨時物件。由於右值引用只能繫結到臨時物件,我們得知
- 所引用的物件將要被銷燬
- 該物件沒有其他使用者
這兩個特性意味著:使用右值引用的程式碼可以自由地接管所引用的物件的資源。
變數是左值
變數可以看作只有一個運算物件而沒有運算子的表示式,雖然我們很少這樣看待變數。類似其他任何表示式,變數表示式也有左值/右值屬性。變數表示式都是左值。帶來的結果就是,我們不能將一個右值引用繫結到一個右值引用型別的變數上,這有些令人驚訝:
int &&rr1 = 42; //正確:字面常量是右值
int &&rr2 = rrl; //錯誤:表示式rr1 是左值!
其實有了右值表示臨時物件這一觀察結果,變數是左值這一特性並不令人驚訝。畢竟,變數是持久的,直至離開作用域時才被銷燬。
// decltype 對變數加上(),返回左值引用。
《C++ Primer》 P471