2023-3-9-一篇简短的文章把C++左右值关系讲的透透彻彻

简介: 2023-3-9-一篇简短的文章把C++左右值关系讲的透透彻彻

前言

对于C++的左值和右值相信很多人都没有一个很透彻的了解,之前我也是不懂的时候查阅了好多文章,但是讲完我还是一头雾水,直到我遇到一篇宝藏文章,讲的左值右值的关系以及Move函数的用法是相当的清楚,文章链接在这,话不多说讲解一下

文章链接


C++左值和右值

在 C++ 或者 C 语言中,一个表达式(可以是字面量、变量、对象、函数的返回值等)根据其使用场景不同,分为左值表达式右值表达式。确切的说 C++ 中左值和右值的概念是从 C 语言继承过来的。

左值的英文简写为“lvalue”,右值的英文简写为“rvalue”。很多人认为它们分别是"left value"、“right value” 的缩写,其实不然。lvalue 是“loactor value”的缩写,可意为存储在内存中、有明确存储地址(可寻址)的数据,而 rvalue 译为 “read value”,指的是那些可以提供数据值的数据(不一定可以寻址,例如存储于寄存器中的数据)。

判断某个表达式是左值还是右值的方法:

① 可位于赋值号(=)左侧的表达式就是左值;反之,只能位于赋值号右侧的表达式就是右值。

int a = 5;
5 = a; //错误,5 不能为左值
/*
其中a是一个左值,字面值5是一个右值
*/

【注意】 C++中的左值也可以当作右值使用。

int b = 10; // b 是一个左值
a = b; // a、b 都是左值,只不过将 b 可以当做右值使用

② 有名称的、可以获取到存储地址的表达式即为左值;反之则是右值。

上述示例中变量 a、b 是变量名且通过 &a 和 &b 可以获得他们的存储地址,因此 a 和 b 都是左值;反之,字面量 5、10,它们既没有名称,也无法获取其存储地址(字面量通常存储在寄存器中,或者和代码存储在一起),因此 5、10 都是右值。


二、右值引用

1.右值引用的引入

在C++11之前就有引用“&”,但是此种引用有一个缺陷,即正常情况下只能操作 C++ 中的左值,无法对右值添加引用。

int num = 10;
int &b = num; //正确
int &c = 10; //错误

编译器允许我们为 num 左值建立一个引用,但不可以为 10 这个右值建立引用。

“&”表示的引用又称为左值引用。

【注意】虽然 C++98/03 标准不支持为右值建立非常量左值引用,但允许使用常量左值引用操作右值。也就是说,常量左值引用既可以操作左值,也可以操作右值。

int num = 10;
const int &b = num;
const int &c = 10;

右值往往是没有名称的,因此要使用它只能借助引用的方式。这就产生一个问题,实际开发中我们可能需要对右值进行修改(实现移动语义时就需要),显然左值引用的方式是行不通的。

为此,C++11 标准新引入了另一种引用方式,称为右值引用,用 “&&” 表示。

2.右值引用的使用

① 和声明左值引用一样,右值引用也必须立即进行初始化操作,且只能使用右值进行初始化。

int num = 10;
//int && a = num;  //右值引用不能初始化为左值
int && a = 10;

② 右值引用可以修改右值

int && a = 10;
a = 11;
cout << a << endl;   //输出结果为11

③C++语法之词定义常量右值引用

const int&& a = 10;//编译器不会报错

但这种形式的右值引用并没有实际用处。一方面,右值引用主要用于移动语义和完美转发,其中前者需要有修改右值的权限;其次,常量右值引用的作用就是引用一个不可修改的右值,这项工作完全可以交给常量左值引用完成。

【总结】

①非常量左值引用可以引用的值的类型只有非常量左值,常量左值引用非常量左值、常量左值及右值

int num = 10;
  int& a = num; //编译成功,非常量左值引用支持引用非常量左值
  const int num2 = 100;
  int& b = num2;  //编译失败,非常量左值引用不支持引用常量左值
  int& c = 10;  //编译失败,非常量左值引用不支持引用右值
  const int& d = num;   //编译成功,常量左值引用支持引用非常量左值
  const int& e = num2;  //编译成功,常量左值引用支持引用常量左值
  const int& f = 100;   //编译成功,常量左值引用支持引用右值

②右值引用不支持引用左值;非常量右值引用可以引用的值的类型只有非常量右值,常量右值引用非常量右值、常量右值

int num = 10;
  const int num2 = 100;
  int&& a = num;  //编译失败,非常量右值引用不支持引用非常量左值
  int&& b = num2; //编译失败,非常量右值引用不支持引用常量左值
  int&& c =10;  //编译成功,非常量右值引用支持引用非常量右值
  const int&& d = num;  //编译失败,常量右值引用不支持引用非常量左值
  const int&& e = num2; //编译失败,常量右值引用不支持引用常量左值
  const int&& f = 100;  //编译成功,常量右值引用支持引用右值

二、右值引用

move()函数的语法格式:

move(arg)
//agr:左值对象,该函数返回arg对象的右值形式
int num = 10;
  int&& a = std::move(num);  //编译成功
  cout << a << endl;   //输出结果为10;


目录
相关文章
|
安全 C++
【C++11保姆级教程】移动构造函数(move constructor)和移动赋值操作符(move assignment operator)
【C++11保姆级教程】移动构造函数(move constructor)和移动赋值操作符(move assignment operator)
1627 0
|
编译器 程序员 C++
2023-4-6-C++11、C++14、C++17、C++20版本新特性系统全面的学习!(二)
2023-4-6-C++11、C++14、C++17、C++20版本新特性系统全面的学习!
666 0
2023-4-6-C++11、C++14、C++17、C++20版本新特性系统全面的学习!(二)
|
前端开发 JavaScript API
【第14期】一文读懂前端NueJS框架
【第14期】一文读懂前端NueJS框架
622 0
|
11月前
|
安全 搜索推荐 网络安全
U2F和FIDO2 两种安全认证技术优劣势对比?如何选择?
数字化时代,网络安全至关重要。FIDO U2F和FIDO2是两种领先的安全认证技术,前者通过物理密钥提供双因素认证,后者则支持无密码认证和生物识别,两者均显著提升了账户安全性。本文详细介绍这两种技术的特点、优缺点及其应用场景,帮助企业选择最适合的安全认证方案。
960 7
|
12月前
|
安全 物联网 物联网安全
制定统一的物联网技术标准和规范的难点有哪些?
制定统一的物联网技术标准和规范的难点有哪些?
425 58
|
网络协议 安全 Unix
socat神器解密:网络数据传输的利器
socat神器解密:网络数据传输的利器
986 1
用Python实现QQ/微信消息轰炸
用Python实现QQ/微信消息轰炸
|
监控 Shell 开发工具
Debian安装与基本使用:详细指南及常见问题解析
【4月更文挑战第13天】本文档介绍了Debian的安装步骤、基本使用、问题解析及进阶技巧。首先,安装Debian涉及下载ISO镜像,制作启动介质,设置BIOS,然后进行安装过程,包括选择语言、分区、网络配置、软件包选择和用户账户设置。安装完成后,学会基本操作,如命令行使用、软件管理(apt)、系统更新和维护。遇到问题时,解决无线网络、分辨率、输入法和依赖问题。进阶技巧包括自定义Shell环境、使用虚拟化技术(Docker、LXC/LXD)、系统监控与性能调优,以及Git和自动化脚本的高级应用。通过学习这些技巧,可提升在Debian系统上的工作效率。
2048 0
|
算法 Python
利用贝叶斯算法对简单应用实现预测分类
利用贝叶斯算法对简单应用实现预测分类
192 0
|
Kubernetes PyTorch 算法框架/工具
pytorch任务无法kill,导致pod退出失败
问题现象pytorch进程通过k8s方式部署,由于该任务无法退出,导致所在的pod也无法退出;再次向pytorch任务发送SIGKILL信号也无法杀死。kenrel版本5.10。任务状态信息pytorch进程状态可以看到pending了一个SIGKILL信号(0x100表示第9为被置1,即SIGKILL信号),man手册中也明确了SIGKILL无法被捕获、阻塞忽略等。另外即使是两个不同的pid n
381 0
pytorch任务无法kill,导致pod退出失败