C++11 左值和右值概述及示例
概念整理
-
左值和右值:
- 左值(Lvalue):可以取地址、有名字的表达式。如普通变量,可以通过 & 操作符获取其地址。
- 右值(Rvalue):不能取地址、没有名字的表达式。如字面量、临时对象。右值又可以细分为纯右值和将亡值。
-
C++11 中右值的扩充:
- 纯右值(Pure Rvalue 或 prvalue):临时变量和不与对象关联的字面量值。类似于 C++98 标准中的右值。
- 将亡值(Expiring Value 或 xvalue):与右值引用相关的表达式,通常是将要被移动的对象,如 T&& 函数返回值、std::move 的返回值。
-
引用类型:
- 左值引用:对一个左值的引用。左值引用是具名变量值的别名。
- 右值引用:对一个右值的引用,右值引用是不具名(匿名)变量的别名。右值引用通常用于移动语义。
示例代码及注释
#include <iostream>
#include <utility> // for std::move
// 函数返回一个右值引用
int&& getRvalue() {
int a = 10;
return std::move(a);
}
void demonstrate() {
int a = 5; // a 是一个左值
int b = a + 3; // a 是左值,a + 3 是右值(具体来说是纯右值)
int&& rvalue = 10; // 10 是右值,rvalue 是右值引用,可以绑定右值
int&& expiring = getRvalue(); // getRvalue() 返回一个将亡值,expiring 是右值引用
const int& constLvalueRef = 20; // 常量左值引用可以绑定右值
int c = 6;
int&& rvalueFromLvalue = std::move(c); // std::move 将 c 转换为右值,rvalueFromLvalue 是右值引用
// 注意,c 此时已经变为一个“将亡值”
// 注释展示变量类型和属性
std::cout << "a (left value): " << a << "\n";
std::cout << "b (right value): " << b << "\n";
std::cout << "rvalue (right value reference): " << rvalue << "\n";
std::cout << "expiring (expiring value reference): " << expiring << "\n";
std::cout << "constLvalueRef (const left value reference): " << constLvalueRef << "\n";
std::cout << "rvalueFromLvalue (right value reference from moved left value): " << rvalueFromLvalue << "\n";
}
int main() {
demonstrate();
return 0;
}
注释解析
-
示例中
左值和纯右值
:a
是一个左值,因为它是一个有名字的变量,可以取其地址&a
。- 表达式
a + 3
是一个右值(纯右值),不能取其地址。
-
右值引用
和将亡值引用
:int&& rvalue = 10;
右值引用rvalue
绑定到右值10
。int&& expiring = getRvalue();
返回一个将亡值(右值引用),expiring
绑定到由std::move(a)
产生的将亡值。
-
std::move
用法:std::move
用于将一个左值转换为右值,以便将其传递给右值引用。示例中,std::move(c)
将c
转换为一个右值,使得rvalueFromLvalue
绑定到这个右值。
-
常量左值引用:
const int& constLvalueRef = 20;
常量左值引用可以绑定到右值,使得常量右值的生命周期延长到引用的生命周期。
-
移动语义的演示:
- 演示如何用
std::move
将左值转换为右值,从而实现移动语义,提高程序的性能。原有的左值c
被移动之后,处于“将亡”的状态。
- 演示如何用
通过这些示例代码和注释,我们能更清晰地理解左值、右值、纯右值、将亡值、左值引用和右值引用的概念及其在 C++11 中的用法。