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.mzph.cn/web/39464.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每日一题——Python实现PAT乙级1026 程序运行时间(举一反三+思想解读+逐步优化)五千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页:用哲学编程-CSDN博客专栏:每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 代码结构和逻辑 时间复杂度 空间复杂度 代码优化建议 总结 我要更强 …

交换机需要多大 buffer

有点违背直觉,但是真事儿,交换机过境的流越多,所需 buffer 越小,这是为什么? 范氏(范雅各布森,van jacobson)管道的 aimd 流建议 buffer_size 为 bdp,这很容易理解,因为 aimd 流最小…

币界网讯,预计以太坊现货 ETF 将于 7 月中旬推出

刚刚 ETF Store 总裁 Nate Geraci 在 X (前Twitter)平台上宣布,备受数字货币市场期待的SEC以太坊现货 ETF提案,将于7 月中旬通过美国证券交易委员会(SEC)批准。Nate Geraci透露修订后的 S-1 文件将于 7 月 …

pnpm的坑

请问pnpm的两个坑怎么解决: 第一个坑:没有节省磁盘空间 我已经配置了依赖的存储位置, 但我在项目里pnpm install以后,发现依赖包还是很大, 然后发现里面的链接并不是指向先前配置的依赖存储位置,而是指…

【数智化人物展】袋鼠云CEO宁海元:大模型时代,Data+AI将成为新的基础设施

宁海元 本文由袋鼠云CEO宁海元投递并参与由数据猿联合上海大数据联盟共同推出的《2024中国数智化转型升级先锋人物》榜单/奖项评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 身处这个瞬息万变的数字经济时代,传统的生产模式往往依赖于经验和固定的流程&…

k8s-第六节-数据持久化

数据持久化 kubernetes 集群不会为你处理数据的存储,需要为数据库挂载一个磁盘来确保数据的安全。 可以选择云存储、本地磁盘、NFS。 本地磁盘:可以挂载某个节点上的目录,但是这需要限定 pod 在这个节点上运行 云存储:不限定节…

GEE计算遥感生态指数RESI

目录 RESI湿度绿度热度干度源代码归一化函数代码解释整体的代码功能解释:导出RSEI计算结果参考文献RESI RSEI = f (Greenness,Wetness,Heat,Dryness)其遥感定义为: RSEI = f (VI,Wet,LST,SI)式中:Greenness 为绿度;Wetness 为湿度;Thermal为热度;Dryness 为干度;VI 为植被指数…

手写starter核心思路流程-全网最详细版本

全网最详细手写starter组件教程 那么在写这篇博客之前,先问一下大家为什么要写starter组件,仅仅只是为了炫技吗?还是真正的在业务中需要.在现在的开发环境下,什么是竞争力? 举例分页查询来说,每个来公司的程序员都有一套自己写分页的流程,但是这套流程基本上都是重复的,那么…

Docker学习笔记(一)概念理解

一、什么是docker容器 Docker容器是一种轻量级、可移植的软件封装技术,它允许开发者将应用程序及其依赖、配置文件、运行环境等打包到一个独立的、自包含的执行单元中。容器与虚拟机相似,都提供了隔离的运行环境,但容器更加轻量级&#xff0c…

如何清理电脑内存?让电脑运行如飞!

电脑内存(RAM)的清理对于维持系统的流畅运行至关重要。随着使用时间的增加,系统内存会被各种应用程序和后台进程占用,导致系统响应变慢,甚至出现卡顿现象。通过有效地清理内存,可以提升电脑的性能&#xff…

深入理解如何撤销 Git 中不想提交的文件

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119qq.com] &#x1f4f1…

MySQL内存使用率高且不释放问题排查与总结

背景 生产环境mysql 5.7内存占用超过90%以上,且一直下不来。截图如下: 原因分析 1、确定mysql具体的占用内存大小,通过命令:cat /proc/Mysql进程ID/status查看 命令执行后的结果比较多(其他参数的含义想了解可参考这…

静态路由的配置

5.3静态路由 静态路由由网络管理员手动配置,配置方便,对系统要求低,适用于拓扑结构简单并且稳定的小型网络。缺点是不能自动适应网络拓扑的变化,需要人工干预。 5.3.1静态路由实验 1、实验需求 ① 掌握路由表的概念&#xff1…

cpp随笔——如何实现一个简单的进程心跳功能

什么是进程的心跳 在我们日常后台服务程序运行中,一般是调度模块,进程心跳以及进程监控共同工作,进而实现实现服务的稳定运行,在前面我们介绍过如何去实现一个简单的调度模块,而今天我们所要介绍的就是如何实现进程的心跳,首先什么是进程的心…

git上传文件

git init git add . git commit -m " " git remote add origin 仓库的地址 git push -u origin master 如果出现以下问题 可以用这一句强制上传 git push -f origin master

Centos下rpm和yum执行卡住问题(已解决)

问题描述 执行rpm和yum卡住, 没有任何报错信息,且无法 ctrl c 终止,只能通过后台 kill -9 杀死。 问题排查: 查看yum日志:yum -vv 软件包 会发现卡在 loading keyring from rpmdb,即load DB存在问题。 …

使用 llamaIndex 快速实现智能体

AI 智能体就是可以根据当前环境进行推理,并根据处理结果进行下一步的操作。简单来说 AI 智能体可以与外界环境进行交互,并根据结果执行更复杂的操作。本文将通过llamaIndex 实现一个简单的 Agent 实时获取数据,由于大模型是通过静态数据进行训…

收银系统源码分享-PHP可二开

千呼新零售2.0系统是零售行业连锁店一体化收银系统,包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体,线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物等连锁店使用。 私有化独立…

游戏工作室如何巧妙应对IP封禁风险?

游戏工作室在使用IP时,面临着封号的风险,因此需要采取一些防封技巧来保护自己的运营。以下是一些游戏工作室常用的防封技巧。 1. 多IP轮换 游戏工作室可以使用多个代理IP,并定期轮换它们。这样做可以减少单个IP被频繁访问同一游戏服务器而被…

C++_03

1、构造函数 1.1 什么是构造函数 类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。 每次构造的是构造成员变量的初始化值,内存空间等。 构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不…