C++左值與右值核心判斷方法
引言
在 C++ 學(xué)習(xí)中,"左值"和"右值"是繞不開的核心概念。它們是理解引用、移動語義、完美轉(zhuǎn)發(fā)的基礎(chǔ)。很多 C++ 程序員寫了多年代碼,仍然對"為什么這里能綁、那里不能綁"感到困惑——根本原因就是沒搞懂左值右值的判斷規(guī)則。
C++ 11 引入右值引用和移動語義后,左值右值的區(qū)分變得更加重要。本文作為系列第一篇,將聚焦最基礎(chǔ)的問題:什么是左值?什么是右值?如何判斷?

第一部分:表達式的兩個屬性
C++ 中每個表達式都有兩個獨立屬性:

第二部分:左值 (lvalue)
一、定義
左值 = 有身份、可尋址的表達式。通俗說就是能取地址的、有名字的東西。
二、判斷法則
核心法則:能用 & 取地址的表達式就是左值。
int main() {
int x = 10; // x 是左值
int* p = &x; // ? 可以對 x 取地址
int y = 20;
int* p2 = &(x + y); // ? 錯誤!x+y 是臨時結(jié)果,不能取地址
return 0;
}三、哪些是左值
| 類別 | 示例 | 說明 |
|---|---|---|
| 變量名 | x、name、vec | 最常見 |
| 解引用指針 | *p | 指針指向的對象 |
| 數(shù)組元素 | arr[3] | 數(shù)組元素有確定位置 |
| 成員變量 | obj.member | 對象成員有地址 |
| 返回左值引用的函數(shù) | vec.front() | 返回的是引用 |
| 賦值表達式 | (a = b) | 賦值返回左值 |
| 字符串字面量 | "hello" | 唯一能取地址的字面量(C 語言遺留) |
int x = 10; // x 是左值
int* p = &x; // *p 是左值(可以 &(*p))
int arr[5] = {1,2,3}; // arr[2] 是左值
string s = "hello";
s[0]; // 左值,返回 char&
int a = 1, b = 2;
(a = b) = 3; // 合法!賦值表達式返回左值第三部分:右值 (rvalue)
一、定義
右值 = 臨時對象、字面量、不能取地址的表達式。右值又細分為純右值和將亡值。

二、純右值 (prvalue)
純右值 = 純粹的臨時值,沒有地址,馬上就要消失
42; // 純右值:整數(shù)字面量
3.14; // 純右值:浮點字面量
true; // 純右值:布爾字面量
a + b; // 純右值:運算產(chǎn)生的臨時結(jié)果
&a; // 純右值:取地址產(chǎn)生的臨時指針
[](int x){return x;}; // 純右值:Lambda 表達式
三、將亡值 (xvalue)
將亡值 = 即將被移動、資源將要被轉(zhuǎn)移的表達式。C++11 新增,主要用于移動語義。
#include <utility>
int x = 10;
std::move(x); // 將亡值:把 x 轉(zhuǎn)成右值
string getString() {
return "hello";
}
getString(); // 純右值(C++17 前)/ 將亡值(特殊情況)四、哪些是右值
| 類別 | 示例 | 說明 |
|---|---|---|
| 數(shù)字字面量 | 42、3.14 | 不能取地址 |
| 布爾字面量 | true、false | 不能取地址 |
| 算術(shù)結(jié)果 | a + b、x * y | 臨時結(jié)果 |
| 取地址結(jié)果 | &a | 臨時指針 |
| Lambda | []{} | 匿名函數(shù)對象 |
std::move(x) | std::move(x) | 強制轉(zhuǎn)右值 |
| 返回非引用的函數(shù) | getValue() | 臨時對象 |
第四部分:核心判斷法則

最簡單的記憶方式:
| 判斷 | 結(jié)果 |
|---|---|
| 有名字的變量 | 左值 |
| 能放到賦值號左邊 | 左值 |
| 不能取地址的臨時東西 | 右值 |
std::move(x) 的結(jié)果 | 右值(將亡值) |
第五部分:特殊情況的判斷
一、字符串字面量
"hello"; // 左值!C 語言遺留,字符串字面量是 const char[6] &"hello"; // ? 可以取地址! 42; // 右值,普通數(shù)字字面量 &42; // ? 錯誤!不能取地址
字符串字面量是唯一的左值字面量。
二、賦值表達式
int a, b; (a = b) = 3; // 合法!賦值表達式返回左值 a = b = c = 0; // 鏈式賦值,就是因為賦值返回左值 // C++ 中 = // 1. 把右邊的值賦給左邊 // 2. 整個表達式返回左邊的引用(左值)
三、前置自增 vs 后置自增
int x = 10; ++x; // 返回 x 的引用 → 左值 x++; // 返回 x 的舊值(臨時)→ 右值 ++++x; // ? 合法(++x 是左值,可以再 ++) x++++; // ? 錯誤(x++ 是右值,不能再 ++)
四、條件表達式
int a = 1, b = 2; (a > b ? a : b) = 3; // ? 兩個都是左值 → 結(jié)果是左值 int x = 1; (x > 0 ? x : 0) = 3; // ? 一個左值一個右值 → 結(jié)果是右值
五、成員訪問
struct Point { int x, y; };
Point p = {1, 2};
p.x; // 左值(p 是左值)
Point{3, 4}.x; // C++11 后可以是左值(臨時對象的成員)第六部分:左值引用
一、基本規(guī)則
左值引用 T& 只能綁定到左值。
int x = 10; int& ref1 = x; // ? x 是左值 int& ref2 = 42; // ? 42 是右值 int& ref3 = x + 1; // ? x+1 是右值 int* p = &x; int& ref4 = *p; // ? *p 是左值
二、const 左值引用(萬能引用)
const T& 既可以綁定左值,也可以綁定右值。這是 C++ 早期為了效率(避免拷貝)引入的特例。
const int& ref1 = 10; // ? 合法!綁定右值,生命周期延長 const int& ref2 = x + 1; // ? 合法! int x = 10; const int& ref3 = x; // ? 也可以綁定左值
const T& 為什么能綁定右值? 編譯器會在幕后創(chuàng)建一個臨時變量,把右值存進去,然后讓引用指向它。這個臨時變量的生命周期會延長到引用的生命周期。
// 編譯器大概這樣處理: const int& ref = 42; // ↓ 等價于 // const int __temp = 42; // const int& ref = __temp;
第七部分:類型與值類別的獨立性
一個容易混淆的點:類型和值類別是獨立的。
int&& rref = 10; // rref 的類型是 int&&(右值引用類型)
// 但 rref 本身是一個有名字的變量
// 所以 rref 是左值!
int x = 10;
int&& rref2 = std::move(x); // rref2 的類型是 int&&
// 但 rref2 是左值核心原則:有名字的就是左值,不管它是什么類型。int&& 類型的變量本身也是左值。
void foo(int& x) { cout << "左值引用" << endl; }
void foo(int&& x) { cout << "右值引用" << endl; }
int main() {
int&& rref = 10; // rref 是左值!
foo(rref); // 調(diào)用 foo(int&) — 輸出"左值引用"
foo(std::move(rref)); // 調(diào)用 foo(int&&) — 輸出"右值引用"
}總結(jié)
一、核心判斷法則

二、引用綁定規(guī)則
| 引用類型 | 可以綁定 |
|---|---|
T& | 只能左值 |
const T& | 左值 + 右值(萬能) |
T&& | 只能右值 |
三、一句話記憶
左值是有身份、可尋址、持久存在的表達式(有名字的變量、解引用指針),右值是臨時對象和字面量(不能取地址)。const T& 是萬能引用能綁一切,T& 只能綁左值,T&& 只能綁右值。有名字的 int&& 變量本身是左值。
到此這篇關(guān)于C++左值與右值:核心判斷法則詳解的文章就介紹到這了,更多相關(guān)C++左值與右值內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++結(jié)構(gòu)體與類指針知識點總結(jié)
在本篇文章里小編給大家整理了關(guān)于C++結(jié)構(gòu)體與類指針知識點以及相關(guān)內(nèi)容,有興趣的朋友們參考學(xué)習(xí)下。2019-09-09
使用Objective-C獲取IPHONE手機IMSI序列號
這篇文章主要介紹了使用Objective-C獲取IPHONE手機IMSI序列號的方法以及通過IMSI序列號獲取運營商、手機號的方法,非常的實用,有需要的小伙伴可以參考下。2015-04-04

