值类别 左值引用 右值引用

本文详细介绍了C++中的值类别,包括左值(lvalue)、右值(rvalue)、纯右值(prvalue)和亡值(xvalue)的概念。通过示例和伪代码展示了左值引用(&)和右值引用(&&)的声明、语法及使用场景,帮助读者理解这两种引用的不同之处及其在内存管理中的作用。同时提供了相关的微软文档和cppreference链接供进一步学习。
摘要由CSDN通过智能技术生成

值类别

每个 C++ 表达式(运算符带上其操作数、字面量、变量名等)可按照两种独立的性质加以辨别:类型和值类别 (value category)。每个表达式都具有某种非引用类型,且每个表达式恰属于三种基本值类别之一:纯右值 (prvalue)、亡值 (xvalue)、左值 (lvalue),定义如下:

  • 泛左值 (glvalue)(“泛化 (generalized)”的左值)是其求值确定一个对象、位域或函数的个体的表达式;
  • 纯右值 (prvalue)(“纯 (pure)”的右值)是求值符合下列之一的表达式:
    • 计算某个运算符的操作数的值(这种纯右值没有结果对象),或者
    • 初始化某个对象或位域(称这种纯右值有一个结果对象)。所有类和数组的纯右值都有结果对象,即使它被舍弃也是如此。在某些语境中,将发生临时量实质化,以创建作为其结果对象的临时量;
  • 亡值 (xvalue)(“将亡 (expiring)”的值)是代表其资源能够被重新使用的对象或位域的泛左值;
  • 左值 (lvalue)(如此称呼的历史原因是,左值可以出现于赋值表达式的左边)是非亡值的泛左值;
  • 右值 (rvalue)(如此称呼的历史原因是,右值可以出现于赋值表达式的右边)是纯右值或者亡值。

关系图

Lvalues 和 Rvalues (C++)

expression 表达式
glvalue 泛左值
rvalue 右值
lvalue 左值
xvalue 亡值
prvalue 纯右值

示例

以下示例演示左值和右值的多种正确的和错误的用法:

// lvalues_and_rvalues2.cpp
int main()
{
    int i, j, *p;

    // Correct usage: the variable i is an lvalue and the literal 7 is a prvalue.
    // 用法正确:变量i是左值 ,文本7是纯右值 。
    i = 7;

    // Incorrect usage: The left operand must be an lvalue (C2106).`j * 4` is a prvalue.
    // 用法不正确:左操作数必须是左值(C2106)。'j*4'是纯右值。
    7 = i; // C2106
    j * 4 = 7; // C2106

    // Correct usage: the dereferenced pointer is an lvalue.
    // 用法正确:未引用的指针是左值。
    *p = i;

    // Correct usage: the conditional operator returns an lvalue.
    // 用法正确:条件运算符返回左值。
    ((i < 3) ? i : j) = 7;
    
    // Incorrect usage: the constant ci is a non-modifiable lvalue (C3892).
    // 用法错误:常量ci是不可修改的左值(c3892)。
    const int ci = 7;
    ci = 9; // C3892
}

左值引用声明符: &

保留对象的地址,但行为方式在语法上与对象相似。

语法

type-id & cast-expression

示例

以下示例通过声明 Person 对象和对该对象的引用演示了引用声明符。 由于 rFriend 是对 myFriend 的引用,因此更新任一变量都将更改同一对象。

int main()
{
	// 正确:i是左值,x是左值引用
	int i = 10;
	int& x = i;
	cout << "i:" << i << " x:" << x << endl;
	i = 20;
	x = 30;
	cout << "i:" << i << " x:" << x << endl;

	// 错误:非常量引用的初始值必须为左值
	//int& x = 10; // 10是右值

	// 正确
	const int& c = 10;
}
Output
i:10 x:10
i:30 x:30

反汇编

	int i = 10;
00BE5DB2  mov         dword ptr [i],0Ah  
	int& x = i;
00BE5DB9  lea         eax,[i]  
	int& x = i;
00BE5DBC  mov         dword ptr [x],eax  

	i = 20;
00BE5E22  mov         dword ptr [i],14h  
	x = 30;
00BE5E29  mov         eax,dword ptr [x]  
00BE5E2C  mov         dword ptr [eax],1Eh  
伪代码
int main()
{
	int i = 10;
	int* x = &i;
	cout << "i:" << i << " x:" << *x << endl;
	i = 20;
	*x = 30;
	cout << "i:" << i << " x:" << *x << endl;
}

右值引用声明符: &&

保留对右值表达式的引用。

语法

type-id && cast-expression

示例

#include <iostream>

using namespace std;

int main()
{
	// 错误:无法将右值引用绑定到左值
	//int i = 10; // i是左值
	//int&& x = i;

	// 正确
	int&& x = 10;
	cout << "x:" << x << endl;
	x = 20;
	cout << "x:" << x << endl;
}
Output
x:10
x:20

反汇编

	int&& x = 10;
00DA5DB2  mov         dword ptr [ebp-18h],0Ah  
00DA5DB9  lea         eax,[ebp-18h]  
00DA5DBC  mov         dword ptr [x],eax  

	x = 20;
00DA5E00  mov         eax,dword ptr [x]  
00DA5E03  mov         dword ptr [eax],14h  
伪代码
int main()
{
	int temp = 10;
	int* x = &temp;
	cout << "x:" << *x << endl;

	*x = 20;
	cout << "x:" << *x << endl;
}

相关参考

微软文档(左值和右值)

微软文档(左值引用)

微软文档(右值引用)

cppreference

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值