C++的左值和右值
摘要
C++語言中的左值和右值是困擾我的知識點,今天將學習到的知識點整理一下,以理清概念。本文首先介紹了左值、右值的一般分類和概念,包括廣義左值,將亡值和純右值,然后介紹了我對左值和右值的理解:將左值理解成水桶,將右值理解成水,最后介紹了左值引用和對常量的左值引用。
表達式值的分類
本文說的左值(lvalue)和右值(rvalue),其中的“值”就是表達式(expression)的值。C++17標准定義了表達式值的分類,其主要分為3類:
- 廣義左值(glvalue):在程序員編程時,程序員可以取地址的東西(對象、函數)。舉例:變量、函數等。
- 純右值(prvalue):在程序員編程時,程序員不可以取地址的東西。舉例:字面值常量。
- 將亡值(xvalue):本身可以被程序員取地址,但是馬上就不能被取地址了的東西。
這三種類別和左右值的關系圖:

三種類別和左右值的關系圖
總結一下,可以這么理解左值和右值:左值,就是可以取地址的東西;右值就是不可以取地址的東西。
左右值的理解
我把左值理解成水桶,右值理解成水。這樣我感覺比較好記憶和理解。比如:
int x; //x左值,理解成一個水桶
x = 10; // 10是右值,理解成水
int *p = &x; // 可以對水桶取地址,找到放水桶的地址
&10; // 編譯錯誤,水沒有位置,不能取地址
int y = x; // 把x水桶里的水復制一份到y水桶。
又如:
int f() {
int x = 10; // x是一個水桶
return x; //但是要被返回了,也就是這個水桶要被“銷毀”。
}
int main() {
f() = 10; //編譯錯誤,水桶已被銷毀,不能盛水了
return 0;
}
左值引用
左值引用,就是在水桶上貼上了一個標簽,這個標簽代表了水桶(其實變量名字也可以理解成水桶上的標簽)。
比如:
int a = 10;
int &b = a; //貼上標簽
注意到常量的左值引用可以綁定到字面值常量上,也就是說以下代碼是正確的:
const int & c = 10; //編譯正確,但是“10”是右值,理解成水,c是左值引用,理解成標簽。
但是如果把左值引用理解成在水桶上貼標簽的話,以上代碼就與這個理解產生沖突了。畢竟“標簽”不能貼到“水”上。
其實,編譯器會創建一個隱藏的變量來讓引用c
綁定到10
上。比如:
const int & c = 10;
//會被翻譯成這樣:
int __internal_unique_name = 10;
const int& c = __internal_unique_name;
也就是說,編譯器會創建一個左值(理解成“水桶”)來存儲10(理解成“水”),然后再讓引用綁定到該左值上(理解成在水桶上貼標簽)。
總結
本文介紹了對左值和右值的理解。如果有什么錯誤,希望讀者可以批評指正!
參考
- [1]微軟C++文檔
- [2]Internal Pointers的博客