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

news2024/11/25 10:51:36

左值和右值好干嘛?

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

一、什么是左值和右值

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

Ⅰ右值是字面量

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.coloradmin.cn/o/2237914.html

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

相关文章

Rust-AOP编程实战

文章本天成,妙手偶得之。粹然无疵瑕,岂复须人为?君看古彝器,巧拙两无施。汉最近先秦,固已殊淳漓。胡部何为者,豪竹杂哀丝。后夔不复作,千载谁与期? ——《文章》宋陆游 【哲理】文章本是不加人工,天然而成的,是技艺高超的人在偶然间所得到的。其实作者所说的“天成”…

深入了解支持向量机:机器学习中的经典算法

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

第01章 Linux概述及系统环境搭建

目标: ◆ 知道 Linux 是什么&#xff1f;有什么特点&#xff1f; ◆ 知道 Linux 内核及发行版的区别 ◆ 知道 Linux 的应用领域 ◆ 能够在虚拟机软件上新建虚拟机 ◆ 能够在虚拟机中挂载CentOS6.7光盘镜像 ◆ 能够根据需求安装CentOS6.7的操作系统 ◆ 能够对系统进行登录和关闭…

【题解】—— LeetCode一周小结45

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结44 4.平方数之和 题目链接&#xff1a;633. 平方数之和 给定一…

Python爬虫基础-正则表达式!

前言 正则表达式是对字符串的一种逻辑公式&#xff0c;用事先定义好的一些特定字符、及这些特定字符的组合&#xff0c;组成一个“规则的字符串”&#xff0c;此字符串用来表示对字符串的一种“过滤”逻辑。正在在很多开发语言中都存在&#xff0c;而非python独有。对其知识点…

kdump 应该怎么安装 linux-crashdump kdump-tools

sudo apt install linux-crashdump sudo apt install crash sudo apt install kdump-tools 1. 两个工具的关系 linux-crashdump kdump-tools 在 Ubuntu 上安装 kdump 功能&#xff0c;这两个包都是相关的&#xff0c;但有不同的作用. linux-crashdump 是一个元包&#xff08;…

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

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

2024-11-01 - 统一身份认证 - OpenLdap - 中间件 - 流雨声

摘要 2024-11-01 周五 杭州 暴雨 调查问卷: https://www.wjx.cn/vm/exIBFDM.aspx# 2024年转瞬即逝&#xff0c;可是生活还在继续&#xff0c;这里有一项关于人工智能和项目管理对于效能关系的调研问卷&#xff0c;AI 对工作的作用和影响。问卷不采集个人信息&#xff0c;在此…

基于微信小程序的电商平台+LW示例参考

1.项目介绍 系统角色&#xff1a;管理员、普通用户功能模块&#xff1a;管理员&#xff08;用户管理、商品分类、商品管理、订单管理、系统管理等&#xff09;&#xff0c;普通用户&#xff08;个人中心、收藏、我的订单、查看商品等&#xff09;技术选型&#xff1a;SpringBo…

python读取word的自动编号以及添加自动编号

目录 1、读取编号 读取示例 如何判断段落是否有自动编号呢&#xff1f; 如何区分不同的类型编号呢&#xff1f; 2、添加自动编号 有的时候需要提取word中带自动编号的信息。对于word中的文字很多第三方的库都可以搞定&#xff0c;但是&#xff0c;提取格式&#xff0c;可能…

ImportError: cannot import name ‘packaging‘ from ‘pkg_resources‘ 的参考解决方法

文章目录 写在前面一、问题描述二、解决方法参考链接 写在前面 自己的测试环境&#xff1a; Ubuntu20.04 ROS-Noetic 一、问题描述 自己在通过 pip install 安装module时 &#xff08;使用的是 pip install mmcv&#xff09;遇到如下问题&#xff1a; ImportError: cannot …

【论文笔记】Wings: Learning Multimodal LLMs without Text-only Forgetting

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: Wings: Learning Multimod…

Tomasulo算法介绍

Tomasulo算法详细解释 #mermaid-svg-x5G4yi740f0ju3OB {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-x5G4yi740f0ju3OB .error-icon{fill:#552222;}#mermaid-svg-x5G4yi740f0ju3OB .error-text{fill:#552222;strok…

【C++练习】二进制到十进制的转换器

题目&#xff1a;二进制到十进制的转换器 描述 编写一个程序&#xff0c;将用户输入的8位二进制数转换成对应的十进制数并输出。如果用户输入的二进制数不是8位&#xff0c;则程序应提示用户输入无效&#xff0c;并终止运行。 要求 程序应首先提示用户输入一个8位二进制数。…

量子计算包kaiwu安装过程踩过的坑

目录 1 安装过程 2 官方代码测试 3 踩坑说明 首先&#xff0c;目前的kaiwu版本仅支持python3.8&#xff0c;所以必须要下载python3.8才能运行kaiwu 1 安装过程 step1: 在页面的SDK标签下&#xff0c;找到对应操作系统的kaiwu包。 step2: 下载python3.8到本地&#xff0c;可…

全文检索ElasticSearch到底是什么?

学习ElasticSearch之前&#xff0c;我们先来了解一下搜索 1 搜索是什么 ① 概念&#xff1a;用户输入想要的关键词&#xff0c;返回含有该关键词的所有信息。 ② 场景&#xff1a; ​ 1互联网搜索&#xff1a;谷歌、百度、各种新闻首页&#xff1b; ​ 2 站内搜索&#xff…

海鲜特写镜头视频素材去哪找 热门视频素材网站分享

作为美食自媒体创作者&#xff0c;海鲜特写镜头的视频素材无疑是提升内容吸引力和质量的重要利器。无论你想展示新鲜的海鲜原料、精美的烹饪过程&#xff0c;还是诱人的餐桌美食&#xff0c;精致的海鲜特写镜头都能极大地吸引观众的注意力。那么&#xff0c;问题来了&#xff1…

Unity 如何优雅的限定文本长度, 包含对特殊字符,汉字,数字的处理。实际的案例包括 用户昵称

常规限定文本长度 ( 通过 UntiyEngine.UI.Inputfiled 附带的长度限定 ) 痛点1 无法对中文&#xff0c;数字&#xff0c;英文进行识别&#xff0c;同样数量的汉字和同样数量的英文像素长度是不一样的&#xff0c;当我们限定固定长度后&#xff0c;在界面上的排版不够美观 痛点2…

SH3001姿态解算

姿态角&#xff0c;机体坐标系相对于参考坐标系的角度 旋转的非交换性 姿态角指的是载体坐标系与参考系之间的关系&#xff0c; 欧拉角是描述物体与某个轴(X,Y,Z)的关系&#xff0c;欧拉角属于姿态角的一种常见描述形式&#xff0c;另外两种描述形式就是四元数和和旋转矩阵 飞…