C++——左值和右值的本质区别

左值和右值好干嘛?

深入理解左值和右值可以帮助我们对代码进行优化

一、什么是左值和右值

左值:有某种存储支持的变量
右值:临时值(字面量、函数的结果)

Ⅰ右值是字面量

int yy = 22;

22本身就是一个临时的,系统不会存储它,故22是右值
而yy是一个int型变量,系统会为其开辟一个int大小的内存空间,故yy是左值

这下就应该很容易理解了吧

右值可以赋值给左值,左值不可以赋值给右值

int yy = 99;//右值99可以赋值给左值yy
10 = yy;//左值yy不可以赋值给右值10

其本质是因为左值是有地址的,有存储空间;而右值没有,是一个临时值而已,存活时间不长

这时候就可以优化代码了,我们不需要过于关注右值,因为它活不长,这就涉及到优化的问题了

可以证明字面量是个右值!

Ⅱ右值是函数的结果

①函数无参数

beyond是一个返回一个int的函数,其是一个右值

int year = beyond();year是左值,函数的结果是个右值,右值可以赋值给左值,正确
beyond() = year;报错,因为beyond()是右值,而year是左值,左值不可以赋值给右值

int beyond() 
{return 1993;
}int main() 
{int year = beyond();beyond() = year;//error,表达式必须是可修改的左值return 0;
}

可以证明函数的结果是右值!

②函数有参数

函数beyond接收的参数为左值,因为year是一个int型,有存储地址

beyond(1993);若调用函数beyond,传入右值也是可以的
这种情况,当函数被调用时,会自动通过该右值1993来创建一个左值,例如:int temp = 1993; beyond(temp);

int beyond(int year) 
{return year;
}int main() 
{int year =1993;beyond(year);beyond(1993);//1993为临时变量右值,它会被系统自动转为一个左值使用return 0;
}

二、左值引用

Ⅰ函数返回类型为左值引用

函数beyond返回值为左值引用(int&),也就是return year;这个左值的引用
这下子,函数的结果就变成了左值,其值就是左值year
int year = beyond();左值引用beyond可以赋值给左值
beyond() = 1999;因为beyond()时左值,故可以将右值1999赋值给左值beyond()

#include <iostream>int& beyond()
{int year = 1993;std::cout << "beyond_year: " << year << std::endl;return year;
}int main()
{int year = beyond();//√beyond() = 1999;//√return 0;
}

Ⅱ函数参数为左值引用

函数beyond的参数为左值引用(int& year),int year是个左值,取它的引用

void beyond(int& year){}int main()
{int year = 1993;beyond(year);//√beyond(1993);//× 非常量引用的初始值必须为左值return 0;
}

可以看到,函数参数为左值引用,若传入一个右值会报错!
变通方法:加上const即可
这也是很多项目里面函数参数常使用const的原因之一,因为函数参数可以传入左值和右值

const int& year加上const就可以了,既可以传入左值,也可以传入右值

void beyond(const int& year){}int main()
{int year = 1993;beyond(year);//√beyond(1993);//√return 0;
}

const+左值引用的本质

右值10是不可以赋值给左值引用int &a的

int& a = 10;//×

若加上const就可以了,因为有编译器默默的进行了转换,将右值10转换为一个临时变量temp,然后把这个临时变量赋值给左值

const int& a = 10;//√//等价于
int temp = 10;
int &a = temp;

const int&可以接收左值和右值,建议使用

Ⅲ如何判断是左值还是右值

写个函数,函数的参数是左值引用即可,因为右值的话传不进来
vocal、guitarist 、band 是左值
"Huangjiaju"、"Huangguanzhong"和vocal + guitarist是右值
其中vocal + guitarist组成了一个临时字符串,然后赋值给左值band
临时值也就是右值,没有地址

#include <iostream>void beyond(std::string& name)
{std::cout << name << std::endl;
}int main()
{std::string vocal = "Huangjiaju";std::string guitarist = "Huangguanzhong";std::string band = vocal + guitarist;beyond(vocal);beyond(guitarist);beyond(band);beyond(vocal + guitarist);//×return 0;
}

常量引用(如const int&)能兼容临时的右值和实际存在的左值变量

三、右值引用

左值引用(例如:const int&)接收左值,类似的,右值引用接收右值(临时对象)

右值引用,例如:const int&&,相对于左值引用多了一个&

将函数beyond的参数改为右值引用std::string&& name,报错的就是传入左值了

#include <iostream>void beyond(std::string&& name)
{std::cout << name << std::endl;
}int main()
{std::string vocal = "Huangjiaju";std::string guitarist = "Huangguanzhong";std::string band = vocal + guitarist;beyond(vocal);//×beyond(guitarist);//×beyond(band);//×beyond(vocal + guitarist);//√return 0;
}

此时,肯定会有同学发现,若要进行函数重载,一个是const+左值引用;另一个是右值引用会咋样?
const + 左值引用支持左值和右值(const std::string& name
右值引用只能传入右值(std::string&& name

#include <iostream>void beyond(const std::string& name)
{std::cout << "const + 左值引用" << name << std::endl;
}void beyond(std::string&& name)
{std::cout << "右值引用" << name << std::endl;
}int main()
{std::string vocal = "Huangjiaju";std::string guitarist = "Huangguanzhong";std::string band = vocal + guitarist;beyond(vocal);//√beyond(guitarist);//√beyond(band);//√beyond(vocal + guitarist);//√return 0;
}

贴下结果
在这里插入图片描述
分析:可以看到beyond(vocal + guitarist);调用的是右值引用的函数
vocal + guitarist是右值,std::string&& name只能接收右值,const std::string& name既可以接收左值,也可以接收右值
编译器最终选择了std::string&& name
这种设计的主要目的是允许开发者提供特定于右值的优化,如移动语义,从而提高代码的性能

四、小结

左值是有实际内存空间的,右值是临时值
左值引用只接受左值,右值引用只接受右值
左值引用加上const既可以接收左值也可以接收右值

会不会有同学问:为啥没有右值引用加const呢?
是不是小傻蛋?右值就是一个临时值,很快就会消失的,哪来的const修饰?

看了很多博客,解释各有差异,也有很多坑
这是我理解透之后总结出来的,感谢网上的很多博主的博客,看了很多,这里就不一一列举了

如果该篇博文对您产生了一丢丢的帮助,还请各位观众老爷给个赞,谢谢~~

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

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

相关文章

【iOS】知乎日报第三周总结

【iOS】知乎日报第三周总结 文章目录 【iOS】知乎日报第三周总结前言评论区文字评论区的一个展开效果评论区数据的一个请求修改了主页获取数据的逻辑主页无限轮播图图片主色调的一个获取将一些拓展部分的内容写在分类里小结 前言 本周笔者因为金工实习整个项目进展比较慢&#…

OpenAI的Triton能替代Nvidia的CUDA吗

先说我的观点&#xff0c;我觉得可以&#xff0c;但是应该不是现在。 然后得补个概念&#xff0c;啥是Triton OpenAI的Triton 是一种专为高效编写深度学习运算而设计的编程语言和编译器。它旨在简化用户编写针对现代GPU&#xff08;尤其是NVIDIA GPU&#xff09;的自定义运算…

【黑马Redis原理篇】Redis数据结构

视频来源&#xff1a;原理篇[2,15] 文章目录 1.动态字符串SDS1.1 内部结构&#xff1a; 2.IntSet3.Dict3.1 dict的内部结构3.2 dict的扩容 4.ziplist压缩列表5.QuickList6.SkipList跳表7.RedisObject对象8.Redis的五种数据结构8.1 String8.2 List8.3 Set8.4 Zset 有序集合8.5 …

SpringBoot 创建多模块项目 项目分模块 项目简化 打包发布

介绍 在 Spring Boot 中&#xff0c;创建多模块项目可以帮助我们将项目拆分成多个相对独立、可重用的模块&#xff0c;从而使代码结构更清晰&#xff0c;便于管理和维护。通常&#xff0c;这样的做法可以提高开发效率&#xff0c;并且更易于进行版本控制和分布式部署。 项目结…

MySQL 数据库之表操作

1. 创建表 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) [character set 字符集 collate 校验规则 engine 存储引擎];field 表示列名datatype 表示列的类型character set 字符集&#xff0c;如果没有指定字符集&#xff0c;则以所在数据库…

【R78/G15 开发板测评】串口打印 DHT11 温湿度传感器、DS18B20 温度传感器数据,LabVIEW 上位机绘制演化曲线

【R78/G15 开发板测评】串口打印 DHT11 温湿度传感器、DS18B20 温度传感器数据&#xff0c;LabVIEW 上位机绘制演化曲线 主要介绍了 R78/G15 开发板基于 Arduino IDE 环境串口打印温湿度传感器 DHT11 和温度传感器 DS18B20 传感器的数据&#xff0c;并通过LabVIEW上位机绘制演…

Chromium Mojo(IPC)进程通信演示 c++(2)

122版本自带的mojom通信例子associated-interface 仅供学习参考&#xff1a; codelabs\mojo_examples\02-associated-interface-freezing 一、目录结构如图&#xff1a; 二、interface.mojom接口 1、codelabs\mojo_examples\mojom\interface.mojom // Copyright 2023 The C…

「Mac畅玩鸿蒙与硬件32」UI互动应用篇9 - 番茄钟倒计时应用

本篇将带你实现一个番茄钟倒计时应用&#xff0c;用户可以设置专注时间和休息时间的时长&#xff0c;点击“开始专注”或“开始休息”按钮启动计时&#xff0c;应用会在倒计时结束时进行提醒。番茄钟应用对于管理时间、提升工作效率非常有帮助&#xff0c;并且还会加入猫咪图片…

u盘怎么重装电脑系统_u盘重装电脑系统步骤和详细教程【新手宝典】

u盘怎么重装电脑系统&#xff1f;一个u盘怎么重装电脑系统呢&#xff0c;需要将u盘制作成u盘启动盘pe&#xff0c;然后通过U盘启动盘进入pe进行安装系统&#xff0c;下面小编就教大家u盘重装电脑系统步骤和详细教程。 u盘启动是什么意思&#xff1f; U盘启动盘是一种具有特殊功…

Typora导出pdf手动分页和设置字体样式

手动分页 <div style"page-break-after: always;"></div>鼠标点击代码才会显示&#xff0c;不点击会隐藏。导出pdf时&#xff0c;该位置会分页 设置字体大小、加粗、居中、空格 <p style"font-size:30px; font-weight: bold; text-align: cen…

简简单单的UDP

前言 上一篇了解了TCP的三次握手过程&#xff0c;目的、以及如何保证可靠性、序列号与ACK的作用&#xff0c;最后离开的时候四次挥手的内容&#xff0c;这还只是TCP内容中的冰山一角&#xff0c;是不是觉得TCP这个协议非常复杂&#xff0c;这一篇我们来了解下传输层另外一个协…

淘宝/天猫按图搜索商品:taobao.item_search_img API的奇幻之旅

在这个看脸的时代&#xff0c;我们不仅对人要看颜值&#xff0c;连买东西都要“看脸”了。没错&#xff0c;我说的就是淘宝/天猫的按图搜索商品功能——taobao.item_search_img API。这个功能就像是电商平台的“人脸识别”&#xff0c;只不过它认的是商品的颜值。下面&#xff…

软件工程 软考

开发大型软件系统适用螺旋模型或者RUP模型 螺旋模型强调了风险分析&#xff0c;特别适用于庞大而复杂的、高风险的管理信息系统的开发。喷泉模型是一种以用户需求为动力&#xff0c;以对象为为驱动的模型&#xff0c;主要用于描述面向对象的软件开发过程。该模型的各个阶段没有…

STM32F405RGT6单片机原理图、PCB免费分享

大学时机创比赛时画的板子&#xff0c;比到一半因为疫情回家&#xff0c;无后续&#xff0c;&#xff0c;&#xff0c;已打板验证过&#xff0c;使用stm32f405rgt6做主控 下载文件资源如下 原理图文件 pcb文件 外壳模型文件 stm32f405例程 功能 以下功能全部验证通过 4路…

写一个记录函数执行时间的装饰器

装饰器&#xff0c;这可是Python开发中绕不开的经典话题&#xff0c;不论你是写代码的老手&#xff0c;还是刚入行的萌新&#xff0c;都得和它打上几轮交道。而记录函数执行时间这个功能&#xff0c;更是装饰器中的“常客”。 今天我就带大家来全面解锁一下这块儿的知识&#…

Python 桌面应用开发:使用 Tkinter 创建 GUI 应用程序

Python 桌面应用开发&#xff1a;使用 Tkinter 创建 GUI 应用程序 引言 随着计算机技术的飞速发展&#xff0c;桌面应用程序依然在许多领域中发挥着重要作用。Python 作为一种强大的编程语言&#xff0c;提供了多种工具和库来创建桌面应用程序。其中&#xff0c;Tkinter 是 P…

vue3入门知识(一)

vue3简介 性能的提升 打包大小减少41%初次渲染快55%&#xff0c;更新渲染快133%内存减少54% 源码的升级 使用Proxy代替defineProperty实现响应式重写虚拟DOM的实现和Tree-Shaking 新的特性 1. Composition API&#xff08;组合API&#xff09; setupref与reactivecomput…

AI与就业:技术革命下的职业转型与挑战

内容概要 在当今时代&#xff0c;人工智能的迅猛发展正在深刻影响着我们的就业市场。这一技术革命不仅让我们看到了未来的职业转型&#xff0c;还引发了对于新兴技能需求的深思。随着AI技术的普及&#xff0c;许多传统行业面临着巨大的变革压力&#xff0c;同时也为新兴领域创…

小白初入Android_studio所遇到的坑以及怎么解决

1. 安装Android_studio 参考&#xff1a;Android Studio 安装配置教程 - Windows(详细版)-CSDN博客 Android Studio超级详细讲解下载、安装配置教程&#xff08;建议收藏&#xff09;_androidstudio-CSDN博客 想下旧版本的android_studio的地址&#xff08;仅供参考&#xf…

Uubntu下的Boost库安装及使用

一、Boost库介绍 Boost库是为C语言标准库提供扩展的一些C程序库的总称。 Boost库由Boost社区组织开发、维护。其目的是为C程序员提供免费、同行审查的、可移植的程序库。Boost库可以与C标准库共同工作&#xff0c;并且为其提供扩展功能。Boost库使用Boost License来授权使用&…