C++左值/右值/左值引用/右值引用

1)C++入门级小知识,分享给将要学习或者正在学习C++开发的同学。

2)内容属于原创,若转载,请说明出处。

3)提供相关问题有偿答疑和支持。

左值和右值的概念:

早期的c语言中关于左值和右值的定义:
左值是可以位于赋值运算符"="左侧的表达式(当然,左值也可以位于"="的右侧);
右值是不可以位于赋值运算符 "="左侧的表达式;

区分左值和右值的一个简单办法是:看能不能对表达式取地址,如果能,则为左值、当然也可以充当右值,如果不能为右值。

如下:

int a;
int b;
a = b;
b = a;
以上a和b都可以位于运算符=的左侧,因此a,b都是左值;

int c;
c = 100; //ok
100 = c; //err
以上常量100只能位于运算符=的右侧因此常量100是右值

不过在 C++ 里面,左值和右值不能这样定义。根据《C++ Primer》的说法,左值和右值可以这样区分:
一个表达式是左值还是右值,取决于我们使用的是它的值还是它在内存中的位置(作为对象的身份)。
也就是说一个表达式具体是左值还是右值,要根据实际在语句中的含义来确定。

如下:
int foo=100;
int bar;

// 将 foo 的值赋给 bar,保存在 bar 对应的内存中
// foo 在这里作为表达式是右值;bar 在这里作为表达式是左值
// 但是 foo 作为对象,既可以充当左值又可以充当右值
bar = foo;

因为 C++ 中的对象本身可以是一个表达式,所以这里有一个重要的原则,即
在大多数情况下,需要右值的地方可以用左值来替代,但需要左值的地方,一定不能用右值来替代。

又有一个重要的特点,即
左值存放在对象中,有持久的状态;而
右值要么是字面常量,要么是在表达式求值过程中创建的临时对象,没有持久的状态

左值引用和右值引用的概念:
左值引用是常见的引用,所以一般在提到「对象的引用」的时候,指得就是左值引用。
如果我们将一个对象的内存空间绑定到另一个变量上,那么这个变量就是左值引用。
在建立引用的时候,我们是将内存空间绑定,因此我们使用的是一个对象在内存中的位置,这是一个左值。
因此,我们不能将一个右值绑定到左值引用上。另一方面,由于常量左值引用保证了我们不能通过引用改变对应内存空间的值,因此我们可以将右值绑定在常量引用上。

如下是左值引用:(左值引用只能绑定到左值上,const引用除外)
int foo=42;
int& bar = foo;  // OK: foo 在此是左值,将它的内存空间与 bar 绑定在一起
int& baz = 42;   // Err: 42 是右值,不能将它绑定在左值引用上
const int& qux = 42;  // OK: 42 是右值,但是编译器可以为它开辟一块内存空间,绑定在 qux 上


c++11中新加了右值引用&&:
对右值进行绑定的引用就是右值引用,他的语法是这样的A&&,通过双引号来表示绑定类型为A的右值。通过&&我们就可以很方便的绑定右值了;
如下是右值引用:(右值引用也是引用,但是它只能且必须绑定在右值上)。
int foo=42;
int& bar = foo;        // OK: 将 foo 绑定在左值引用上
int&& baz = foo;       // Err: foo 可以是左值,所以不能将它绑定在右值引用上
int&& qux = 42;        // OK: 将右值 42 绑定在右值引用上
int&& quux = foo * 1;  // OK: foo * 1 的结果是一个右值,将它绑定在右值引用上
int& garply = foo++;   // Err: 后置自增运算符返回的是右值,不能将它绑定在左值引用上
int&& waldo = foo--;   // OK: 后置自减运算符返回的是右值,将它绑定在右值引用上

由于右值引用只能绑定在右值上,而右值要么是字面常量,要么是临时对象,所以:
右值引用的对象,是临时的,即将被销毁;并且
右值引用的对象,不会在其它地方使用。

我们思考一个问题:右值引用本身是左值还是右值?或者可以先思考一下它的对偶问题:左值引用本身是左值还是右值?

先看下面的代码:
int foo(42);
int& bar = foo;     // bar 是对 foo 的左值引用
int& baz = bar;     // baz 是对 bar 的左值引用,因而 bar 是右值
int qux = ++foo;    // 前置自增运算符返回左值引用,在这里赋值给 qux,此时左值引用作为右值
观察上面代码,不难发现,左值引用本身既可以是左值,又可以是右值。它具体是左值还是右值,依然取决于它作为表达式时候的作用。更仔细地观察可以发现,
如果左值引用作为一个变量被保存下来了,那么它就可以是左值(当然也可以起到右值的作用);而如果左值引用是一个临时变量(例如函数的返回值),那么它就是右值。

同理可以用在右值引用上。

class Type;
void foo(Type&& bar) {
    // 将右值引用作为 Type 的构造函数的参数
    // 此时匹配 Type::Type(const Type& orig), 即拷贝构造函数
    // bar 是左值
    Type baz(bar);
}
Type&& qux();
quux = qux();   // qux 的返回值是 Type 类型的右值引用,此时右值引用是右值
和左值引用一样,右值引用本身也既可以作为左值也可以作为右值。并且,同样的是:如果右值引用作为变量被保存下来了,那么应该把它当做是一个左值看待;否则应当作为右值看待。

因此,不论是左值引用还是右值引用,都有

当引用作为变量被保存下来,那么它是左值;否则
它是右值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/775792.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用中国大陆镜像源安装最新版的 docker Deamon

在一个智算项目交付过程中,出现了新建集群中的全部 docker server V19 进程消失、仅剩 docker server 的 unix-socket 存活的现象。 为了验证是否是BD产品研发提供的产品deploy语句缺陷,需要在本地环境上部署一个简单的 docker Deamon 环境。尴尬的是&a…

强化学习后的数学原理:随机近似与梯度下降

概述 这节课的作用: 本节课大纲如下: Motivating examples 先回顾一下 mean estimation : 为什么总数反复提到这个 mean estimation,就是因为 RL 当中有非常多的 expectation,后面就会知道除了 state value 这些定义…

传统视觉Transformer的替代者:交叉注意力Transformer(CAT)

传统视觉Transformer的替代者:交叉注意力Transformer(CAT) 在深度学习的世界里,Transformer架构以其在自然语言处理(NLP)领域的卓越表现而闻名。然而,当它进入计算机视觉(CV&#x…

Hilbert编码 思路和scala 代码

需求: 使用Hilbert 曲线对遥感影像瓦片数据进行编码,获取某个区域的编码值即可 Hilbert 曲线编码方式 思路 大致可以对四个方向的数据进行归类 左下左上右上右下 这个也对应着编码的顺序 思考在不同Hilbert深度(阶)情况下的…

AutoX.js某音自动评论(一个函数,5秒完成)

背景 某音自动化评论,步骤简单,对版本兼容性要高(不用节点id定位) 思路 通过Intent直接跳转到视频*利用文字,描述(正则)等匹配输入框,发表评论 效果 某音自动化评论 已经封装成一…

专题二:Spring源码编译

目录 下载源码 配置Gradle 配置环境变量 配置setting文件 配置Spring源码 配置文件调整 问题解决 完整配置 gradel.properties build.gradle settiings.gradel 在专题一: Spring生态初探中我们从整体模块对Spring有个整体的印象,现在正式从最…

C盘扩容/扩大C盘的12个有效操作方法

对于许多计算机用户来说,C盘空间可能会成为一个问题,尤其是那些将计算机广泛用于工作、游戏和多媒体目的的用户。如果您发现C驱动器上的空间不足,则需要对其进行扩展以提高系统的整体性能。在这篇文章中,我们将探讨C盘扩展的12种操…

【计算智能】遗传算法(二):基本遗传算法在优化问题中的应用【实验】

前言 本系列文章架构概览: 本文将介绍基本遗传算法在解决优化问题中的应用,通过实验展示其基本原理和实现过程:选取一个简单的二次函数作为优化目标,并利用基本遗传算法寻找其在指定范围内的最大值。 2. 基本遗传算法(SGA&#x…

Laravel 谨慎使用Storage::append()

在 driver 为 local 时,Storage::append()在高并发下,会存在丢失数据问题,文件被覆写,而非尾部添加,如果明确是本地文件操作,像日志写入,建议使用 Illuminate\Filesystem\Filesystem或者php原生…

跨境干货|最新注册Google账号方法分享

谷歌账号对做跨境外贸业务的人来说是刚需,目前来说大部分的海外社媒平台、工具都可以用谷歌账号来注册。但是仍然有很多朋友并不知道如何注册这个谷歌账号,今天就来给大家分享2个注册谷歌账号的方法,一个是手机号注册,一个是如何跳…

品牌营销新趋势:独立站如何与TikTok达人互动共赢

在当今数字化营销时代,独立站与TikTok达人的互动营销已成为一种高效的推广方式。通过精心设计的互动环节,独立站不仅能够增强用户参与感,还能显著提升带货效果。本文Nox聚星将和大家探讨独立站如何与TikTok达人进行高效互动,吸引用…

如何有效管理你的Facebook时间线?

Facebook作为全球最大的社交平台之一,每天都有大量的信息和内容在用户的时间线上展示。有效管理你的Facebook时间线,不仅可以提升用户体验,还能够帮助你更好地控制信息流和社交互动。本文将探讨多种方法和技巧,帮助你有效管理个人…

开发者评测|操作系统智能助手OS Copilot

操作系统智能助手OS Copilot 文章目录 操作系统智能助手OS CopilotOS Copilot 是什么优势功能 操作步骤创建实验重置密码创建Access Key配置安全组安装 os-copilot环境变量配置功能评测命令行模式多轮交互模式 OS Copilot 产品体验评测反馈OS Copilot 产品功能评测反馈 参考文档…

C++基础(七):类和对象(中-2)

上一篇博客学的默认成员函数是类和对象的最重要的内容,相信大家已经掌握了吧,这一篇博客接着继续剩下的内容,加油! 目录 一、const成员(理解) 1.0 引入 1.1 概念 1.2 总结 1.2.1 对象调用成员函数 …

使用 mongo2neo4j 和 SemSpect 通过各种方式进行图探索

用于可视化和探索每个 MEAN 堆栈背后的数据图的 ETL 您是否正在努力回答有关 MEANS Web 服务数据的紧急问题?哪里有 BI 可以快速回答“上个季度哪些亚洲的artisan.plus 用户触发了订单?”这个问题,而无需编写查询?使用 mongo2neo4…

Linux:进程间通信(一.初识进程间通信、匿名管道与命名管道、共享内存)

上次结束了基础IO:Linux:基础IO(三.软硬链接、动态库和静态库、动精态库的制作和加载) 文章目录 1.认识进程间通信2.管道2.1匿名管道2.2pipe()函数 —创建匿名管道2.3匿名管道的四种情况2.4管道的特征 3.基于管道的进程池设计4.命…

FineBI在线学习资源-数据处理

FineBI在线学习资源汇总: 学习资源 视频课程 帮助文档 问答 数据处理学习文档: 相关资料: 故事背景概述-https://help.fanruan.com/finebi6.0/doc-view-1789.html 基础表处理-https://help.fanruan.com/finebi6.0/doc-view-1791.html …

软件设计之Java入门视频(11)

软件设计之Java入门视频(11) 视频教程来自B站尚硅谷: 尚硅谷Java入门视频教程,宋红康java基础视频 相关文件资料(百度网盘) 提取密码:8op3 idea 下载可以关注 软件管家 公众号 学习内容: 该视频共分为1-7…

Ubuntu 24.04 上安装 Kubernetes,超级详细的教程!

Kubernetes 是一个免费的开源容器编排工具,它允许基于容器的应用程序的自动化部署、扩展和管理。 我们将介绍如何使用 Kubeadm 逐步在 Ubuntu 24.04 上安装 Kubernetes 此次演示中,我们将使用以下三个 Ubuntu 24.04 实例 Instance 1 : Master Node (k…

计算机视觉——opencv快速入门(二) 图像的基本操作

前言 上一篇文章中我们介绍了如何配置opencv,而在这篇文章我们主要介绍的是如何使用opencv来是实现一些常见的图像操作。 图像的读取,显示与存储 读取图像文件 在opencv中我们利用imread函数来读取图像文件,函数语法如下: imagecv2.imre…