一、引子
我們所謂的左值、右值,正確的說法應該是左值表達式、右值表達式。
因為C++的表達式不是左值就是右值。
在C中,左值指的是既能夠出現在等號左邊也能出現在等號右邊的表達式,右值指的則是只能出現在等號右邊的表達式。
而在C++中,二者的區別就不是這么簡單了。
二、關鍵點
【官方定義】
- 一個左值表達式的求值結果是一個對象或者一個函數,而某些右值表達式的求值結果也是對象;
- 以常量對象為代表的某些左值並不能作為賦值語句的左側運算對象。
- 歸納:當一個對象被用作右值的時候,用的是對象的值(內容);而被用作左值的時候,用的是對象的身份(在內存中的位置)。
【解讀定義】
解讀第一句:既然左值和右值都可以是對象,那怎么區分一個對象是左值還是右值呢?
- 左值:能用“取地址&”運算符獲得對象的內存地址
- 右值:不能用“取地址&”運算符獲得對象的內存地址
- 特例:因為可以用&取得字符串字面值常量的地址,所以它是一個左值;而其他的字面值常量則不可用&取地址,所以它們是右值
我們知道對象是一塊空間,那么有哪些對象以及為什么不能用&取地址呢?
- 對於臨時對象,它可以存儲於寄存器中,所以沒辦法用“取地址&”運算符;
- 對於(非字符串)常量,它可能被編碼到機器指令的“立即數”中,所以沒辦法用“取地址&”運算符。
解讀第二句:字符串字面值常量確實不能放在等號左邊啊,沒錯啊!
解讀歸納:所以啊,左值看地址,右值看內容。
【補充】
#include <iostream> using namespace std; int& func(int &a) { return a; // 不能返回局部對象的引用 } int main() { int a = 10; func(a) = 100; // 返回非常量引用的函數可以當作左值使用 cout << a << endl; // 輸出100 return 0; }
三、為什么要區分左值右值
- 不同的運算符對運算對象的要求各不相同,有的需要左值運算對象、有的需要右值運算對象;返回值也有差異,有的得到左值結果、有的得到右值結果。
舉例:使用關鍵字decltype的時候,其表達式的求值結果若是左值,decltype作用於該表達式(不能是變量)得到一個引用類型。例如,p的類型是int *,因為解引用運算符生成左值,所以decltype(*p)的結果是int &。而另一方面,因為取地址運算符生成右值,所以decltype(&p)的結果是int **,即結果是一個指向整型指針的指針。