【C++ | 左值、右值】一文了解C++的左值、右值、左值引用()、右值引用()

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
⏰发布时间⏰:2024-06-12 16:35:55

本文未经允许,不得转发!!!

目录

  • 🎄一、概述
  • 🎄二、左值(lvalue)
  • 🎄三、右值(rvalue)
  • 🎄四、左值引用
  • 🎄五、右值引用(rvalue reference)
    • ✨5.1 右值引用的理解
    • ✨5.2 std::move
  • 🎄六、总结



在这里插入图片描述

🎄一、概述

左值、右值、左值引用、右值引用,这几个概念常常在C++编程中出现,如果没弄清楚这几个概念的意思,有时会在看一些C++书籍时会感到特别困惑。

左值和右值是表达式的属性。一些表达式生成或要求左值,而另外一些则生成或要求右值。一般而言,一个左值表达式表示的是一个对象的身份,而一个右值表达式表示的是对象的值。

左值、右值最初是出现在C语言中的,左值最初指的是可出现在赋值语句左边的实体,引入了const关键字之后,常规变量和 const 变量都可视为左值, 因为可通过地址访问它们,但常规变量属于可修改的左值, 而 const 变量属于不可修改的左值。右值一般是没有明确的内存位置,无法使用&获取地址,值不可被修改。例如:立即数、常量、字面值、&(变量)。

在C++中,增加了引用的概念,所以会出现左值引用、右值引用,下文将举例说明这几个概念。


在这里插入图片描述

🎄二、左值(lvalue)

左值:英文简写为“lvalue”,是“locator value”的缩写,可意为存储在内存中、有明确存储地址(可寻址)的数据。

左值:本质上是可以操作的一块内存区域,一般可以通过&取到该内存起始地址,这块内存的值可以被修改(const对象除外)。除了const对象的其他左值都可以出现在赋值语句左边。

常见的左值有:
1、变量(对象);
2、const 变量(对象);
3、对指针解引用,*(指针)
4、数组元素,a[1]
5、结构体成员、类成员,s.m_aps->ma

// g++ 13_lvalue.cpp
int main()
{int i = 0;			i = 1;				// i是变量(对象),左值const int ci = 5;	//ci = 6;			// ci是const变量(对象),是左值但不能出现在赋值号左边int *pi = &i;*pi = 1;			// *pi 对指针解引用,左值int arr[5] = {0,};arr[0] = 1;			// arr[0] 是数组元素,左值struct {int m_a;int m_b;} st, *pst=&st;st.m_a = 1;			// 结构体成员,左值pst->m_b = 2;return 0;
}

在这里插入图片描述

🎄三、右值(rvalue)

右值:英文简写为“rvalue”,是"read value"的缩写,指的是那些可以提供数据值的数据(不一定可以寻址,例如存储于寄存器中的数据)。

右值:指一种表达式,其结果是值而非值所在的位置。一般是没有明确的内存位置,无法使用&获取地址,值不可被修改的。例如:立即数、常量、字面值、&(变量)。另外,很多时候左值可以当右值使用。

关于右值的,有一个重要的原则,是在需要右值的地方 (除了移动构造函数) 可以用左值来代替,但是不能把右值当成左值(也就是位置)使用。当一个左值被当成右值使用时,实际使用的是它的内容(值)。

常见的右值有:
1、字面常量(立即数),引号括起的字符串除外(它们由其地址表示),42'a'
2、算术运算符(+、-、*、/、%、正号、负号)的求值结果,1+2
3、逻辑运算符(&&、||、!)的求值结果,a!=10
4、关系运算符(>、>=、<、<=、==、!=)的求值结果,a>10 && a<100
5、函数的非引用返回值。这种返回值位于临时内存单元中,运行到下一条语句时,它们可能不再存在;
6、当条件运算符的两个表达式都是左值或者能转换成同一种左值类型时,运算的结果是左值;否则运算的结果是右值。

// g++ 13_rvalue.cppint get100()
{return 100;
}int main()
{int i = 0, c=0;			i = 42;				// 字面值42,右值c = 'a';			// 字面值'a',右值i = 1+2;			// 算术运算符的求值结果,右值i = (c!='a');		// 逻辑运算符的求值结果,右值i = (c >= 'a'); 	// 关系运算符的求值结果,右值i = get100();		// 函数的非引用返回值,右值i>0?i:c = i>0?1:0;	// 条件运算符的两个表达式都是左值,则可以做左值,本例的 i>0?i:c// 条件运算符的两个表达式都是右值,则为右值,本例的 i>0?1:0;i = c;				// c是左值,左值的值可以当右值使用return 0;
}

在这里插入图片描述

🎄四、左值引用

左值引用:左值引用这个词是在C++11增加了右值引用之后才出现,为了与右值引用区分开,把C++11之前出现的引用成为左值引用。所以,左值引用就是C++中的引用类型,是己定义的变量的别名,主要用作函数形参或返回值。

传统的 C++引用(现在称为左值引用) 使得标识符关联到左值,左值引用不能绑定到要求转换的表达式、字面常量或是返回右值的表达式。

const左值引用既可以绑定到左值,也可以绑定到右值。但不能修改const左值引用绑定的内容。

怎样声明、定义左值引用:左值引用的定义需要使用&,格式一般是类型 &变量名 = 变量。左值引用定义必须初始化,且初始化后无法改变该引用关联的对象。下面例子介绍了左值引用的定义、const左值引用初始化为左值、const左值引用初始化为右值,

// g++ 13_lvalue_reference.cpp
int get100()
{return 100;
}
int main()
{int i = 0;int &ri = i;		// 左值引用
//	int &*pri = &ri;	// 不能定义引用的指针。报错:cannot declare pointer to ‘int&’
//	int &&rri = ri;		// 不能定义引用的引用。在C++11标准里,这是一个右值引用int *pi = &i;int *&rpi = pi;		// pi是左值,rpi是指针的引用int &r_pi = *pi;	// *pi是左值,可以初始化左值引用int arr[5] = {0};int &rarr = arr[0];	// arr[0]是左值,可以初始化左值引用// const 左值引用可以被初始化为一些左值const int &cri = i;		// const 左值引用
//	const int *&crpi = pi;	// 报错:用 ‘int*’ 初始化 ‘const int*&’ 无效const int &cr_pi = *pi;	// const 左值引用const int &crarr= arr[0];// const 左值引用可以被初始化为右值const int &ri0 = 42;const int &ri1 = 'a';const int &ri2 = 1+2;const int &ri3 = (ri1 != 'a');const int &ri4 = (ri1 >= 'a');const int &ri5 = get100();		// 函数的非引用返回值,右值const int &ri6 = i>0?1:0;	
//	ri0 = 1;	// 报错,const引用是只读的,其值不能修改return 0;
}

左值引用常用作函数的形参、返回值。返回引用的函数是左值的,意味着这些函数返回的是对象本身而非对象的副本。返回左值引用的函数, 连同赋值、下标、解引用和前置递增/递减运算符, 都是返回左值的表达式的例子。

另外,应尽可能将引用形参声明为 const ,有以下三个理由:
• 使用 const 可以避免无意中修改数据的编程错误;
• 使用 const 使函数能够处理 const 和非 const 实参, 否则将只能接受非 const 数据;
• 使用 const 引用使函数能够正确生成并使用临时变量。

如果实参为右值, const 引用形参将指向一个临时变量。


在这里插入图片描述

🎄五、右值引用(rvalue reference)

右值引用:这是为了支持移动操作,C++11标准引入的一种新的引用类型。所谓右值引用就是必须绑定到右值的引用。我们通过 && 而不是 & 来获得右值引用。编译时,需要加 -std=c++11 来支持C++11标准。

类似任何引用,一个右值引用也不过是某个对象的另一个名字而已。

✨5.1 右值引用的理解

怎样定义右值引用?右值引用使用&&来定义,也是必须初始化,初始化后无法改变其绑定的对象。定义右值引用格式:类型 &&引用名称 = 右值;。定义一个右值引用可以参考下面代码:

int &&rl = 13;
int *pi = &rl;

将右值关联到右值引用导致该右值被存储到特定的位置,且可以获取该位置的地址。也就是说,虽然不能将运算符&用于 13,但可将其用于 rl。通过将数据与特定的地址关联,使得可以通过右值引用来访问该数据。

右值引用只能绑定到一个右值,右值要么是字面常量,要么是在表达式求值过程中创建的临时对象;

而临时对象有两个特点:
1、该对象将要被销毁;
2、该对象没有其他用户再使用它。
这就意味着,右值引用的代码是最后使用这个对象的了,可以自由地接管所引用的对象的资源。

在这里插入图片描述
如上图,变量a、b相加之后会产生一个值,这个值就是临时量,但它在内存中肯定是存在某个地址的,没有右值引用之前,这个值使用完就会被销毁,我们也不会知道它的内存地址。现在,这块内存可以被右值引用关联,关联后,右值引用甚至可以改变内存的内容,等右值引用使用完再销毁。

看看下面关于右值引用的例子,加深理解:

// g++ 13_rvalue_reference.cpp  -std=c++11
#include <iostream>
using namespace std;
int get100()
{return 100;
}void fun(int &&rri)// 右值引用作为函数形参
{rri = 0;
}
int main()
{// 1、右值引用必须被初始化为右值int &&ri0 = 42;		// 将 42 存到一个临时量,然后引用这个临时量int &&ri1 = 'a';	// 将 'a' 存到一个临时量,然后引用这个临时量int &&ri2 = 1+2;	// 将 1+2 存到一个临时量,然后引用这个临时量int &&ri3 = (ri1 != 'a');int &&ri4 = (ri1 >= 'a');int &&ri5 = get100();	// 函数的非引用返回值,右值int &&ri6 = ri0>0?1:0;// 2、右值引用的内容可以被修改ri0 = 1;cout << "ri0=" << ri0 << endl;// 3、虽然没办法获取右值的地址,但可以获取右值引用的地址,并改变该地址的值int *pi = &ri0;*pi = 2;cout << "pi=" << pi << ", *pi=" << *pi << ", ri0=" << ri0 << endl;// 4、传入右值fun(1+2);return 0;
}

✨5.2 std::move

虽然不能将一个右值引用直接绑定到一个左值上, 但我们可以显式地将一个左值转换为对应的右值引用类型。通过调用 std::move 的标准库函数可以获取绑定到左值上的右值引用,此函数定义在 utility 头文件中。

int i = 0;
int &&rri = std::move(i);

std::move 告诉编译器,我们有一个左值,但希望像右值一样处理它。

注意,使用 std::move 函数处理的对象,被成为移后源对象,我们可以修改该对象的值,但不可以再使用这个对象的值了,虽然语法上允许,但可能产生一些不可知的结果。因为调用了std::move 函数处理一个对象,也应被视为即将销毁的对象,如果这个对象还需要在后面的代码使用,则不建议对它调用 std::move 函数处理。


在这里插入图片描述

🎄六、总结

👉本文介绍了C++的左值、右值、左值引用、右值引用。左值一般表示某一块内存,可以获取其地址;右值则一般只表示数据,不能被获取地址,很多情况,左值的值可以是右值;左值引用是某个左值的别名;右值引用是某个右值的别名。

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

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

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

相关文章

CSS真题合集(一)

CSS真题合集&#xff08;一&#xff09; 1. 盒子模型1.1 盒子模型的基本组成1.2 盒子模型的实际大小1.3 盒子模型的两种类型1.4 设置盒子模型1.5 弹性盒子模型 2. BFC2.1 主要用途2.2 触发BFC的方法2.2 解决外边距的塌陷问题&#xff08;垂直塌陷&#xff09; 3. 响应式布局3.1…

LWIP移植

目录 前言一、以太网协议简介1.1 TCP/IP协议简介1.2 STM32的ETH外设1.2.1 MAC子层1.2.2 SMI站管理接口1.2.3 MII和RMII接口 1.3 外部PHY芯片LAN87201.3.1 LAN8720 中断管理1.3.2 PHY 地址设置1.3.3 nINT/REFCLKO 配置1.3.4 LAN8720 内部寄存器 1.4 LWIP 简介 二、带操作系统的移…

pxe批量部署linux介绍

1、PXE批量部署的作用及必要性&#xff1a; 1&#xff09;智能实现操作系统的批量安装&#xff08;无人值守安装&#xff09;2&#xff09;减少管理员工作&#xff0c;提高工作效率3&#xff09;可以定制操作系统的安装流程a.标准流程定制(ks.cfg)b.自定义流程定制(ks.cfg(%pos…

北京医院共享轮椅小程序开发更贴心,更便捷

在大数据不断发展的今天&#xff0c;资源共享已随处可见&#xff0c;小到共享充电宝&#xff0c;共享雨伞&#xff0c;大到共享单车&#xff0c;汽车。这些常用资源的共享&#xff0c;充分实现了有限资源的最大化利用。 如今&#xff0c;众多北京医院&#xff0c;也结合自身实…

15.RedHat认证-Ansible自动化运维(上)

15.RedHat认证-Ansible自动化运维(上) RHCE8-RH294 Ansible自动化&#xff08;Ansible版本是2.8.2&#xff09; Ansible介绍 1.Ansible是什么&#xff1f; Ansible是一个简单的强大的无代理的自动化运维工具&#xff08;Ansible是自动化运维工具&#xff09;Ansible特点 简…

Anconda安装

参考: centos7篇---安装anaconda_centos7安装anaconda-CSDN博客 CentOS 7 上安装 Anaconda_centos安装conda-CSDN博客 CentOS7 安装Anaconda 的步骤_centos7安装anaconda-CSDN博客 centos7 如何安装与使用 Anaconda - 码农教程 下载 wget命令 wget https://repo.anaconda…

springboot+minio+kkfileview实现文件的在线预览

在原来的文章中已经讲述过springbootminio的开发过程&#xff0c;这里不做讲述。 原文章地址&#xff1a; https://blog.csdn.net/qq_39990869/article/details/131598884?spm1001.2014.3001.5501 如果你的项目只是需要在线预览图片或者视频那么可以使用minio自己的预览地址进…

Linux Ext2/3/4文件系统

文章目录 前言一、Linux文件系统简介1.1 简介1.2 Linux File System Structure1.3 Directory Structure 二、Ext2/3/4文件系统2.1 Minix2.2 EXT2.3 EXT22.4 EXT32.5 EXT4 三、EXT Inode参考资料 前言 这篇文章介绍了Linux文件系统的一些基础知识&#xff1a;Linux 文件系统简介…

推荐网站(22)GeoSpy,根据图片显示地理位置

今天推荐一款名为GeoSpy的AI工具。它利用人工智能技术&#xff0c;通过分析照片中的光线、植被、建筑风格等细节线索&#xff0c;实现对拍摄地点的精确定位。令人难以置信的是,它对位置的定位准确度非常高。 GeoSpy之所以智能如此,是因为它将输入的照片与大量的街景和地理图像…

【LLM】度小满金融大模型技术创新与应用探索

note 从通用大模型到金融大模型金融大模型的训练技术创新金融大模型的评测方法创新金融大模型的应用实践创新总结&#xff1a;金融大模型迭代路径 一、轩辕大模型 二、垂直大模型训练 1. 数据准备 数据质量是模型效果的保障。首先数据要丰富&#xff0c;这是必备的条件。我们…

YASKAWA机器人HW1171921-B电缆维修

安川机器人作为现代工业自动化的重要设备&#xff0c;其稳定运行对于生产线的连续性和效率至关重要。然而&#xff0c;随着使用时间的增长&#xff0c;可能会出现各种YASKAWA机器人本体线缆故障&#xff0c;如断线、短路、接触不良等。 一、安川工业机器人电缆维修前的准备 在进…

大模型的现状与未来:探索腾讯元宝APP及其他AIGC产品

前言 随着近日腾讯元宝APP的正式上线&#xff0c;国内大模型产品又添一员。近年来&#xff0c;随着人工智能技术的快速发展&#xff0c;AIGC&#xff08;AI生成内容&#xff09;产品逐渐成为技术与商业应用的热点。各大互联网厂商纷纷推出自己的大模型产品&#xff0c;以期在这…

疑惑...2024年是不是转行AI产品经理的好时机?

前言 这两年AI突然“火起来” 了 &#xff0c;算是出现了一个“大转折”。 因为就在这2年里&#xff0c;全球所有“大厂”几乎同一时间挤破头在跟进AI技术&#xff0c;从ChatGPT发布&#xff0c;到谷歌、Facebook、亚马逊等都紧跟其后&#xff0c;再到国内百度、腾讯、阿里、…

蓝牙芯片TD5322A,蓝牙5.1数传芯片介绍—拓达半导体

蓝牙芯片原厂&#xff0c;拓达芯片TD5322A是一颗支持蓝牙BLE和SPP的数传芯片&#xff0c;蓝牙5.1版本。芯片的优点是尺寸小(SOP-8封装&#xff09;&#xff0c;性能强&#xff0c;价格低&#xff0c;以及简单明了的透传和串口AT控制功能&#xff0c;大大降低了在其它电子产品中…

C++学习笔记(23)——二叉树进阶

系列文章 http://t.csdnimg.cn/QDR3y 目录 系列文章[TOC](目录) 1. 二叉树的优势2. 二叉搜索树概念3. 二叉搜索树操作1. 二叉搜索树的查找2. 二叉搜索树的插入——地址链接重设3. 二叉搜索树的删除——地址链接重设 4. 二叉搜索树的应用——以key为载体&#xff0c;承载复杂信…

在矩池云使用GLM-4的详细指南(无感连GitHubHuggingFace)

GLM-4-9B 是智谱 AI 推出的最新一代预训练模型 GLM-4 系列中的开源版本&#xff0c;在多项测试中表现出超越已有同等规模开源模型的性能&#xff0c;它能兼顾多轮对话、网页浏览、代码执行、多语言、长文本推理等多种功能&#xff0c;性能更加强大。其多模态语言模型GLM-4V-9B在…

生产环境部署meilisearch(Running a self-hosted Meilisearch project in production)

官网的第一手资料学新技术&#xff1a;meilisearch官方文档 安装的官网地址&#xff1a;meilisearch安装的官网 部署在生产环境的指导&#xff1a;meilisearch部署在生产环境的指导 Elasticsearch 做为老牌搜索引擎&#xff0c;功能基本满足&#xff0c;但复杂&#xff0c;重…

vscode软件上安装 Fitten Code插件及使用

一. 简介 前面几篇文章学习了 Pycharm开发工具上安装 Fitten Code插件&#xff0c;以及 Fitten Code插件的使用。 Fitten Code插件是是一款由非十大模型驱动的 AI 编程助手&#xff0c;它可以自动生成代码&#xff0c;提升开发效率&#xff0c;帮您调试 Bug&#xff0c;节省…

Qt5/6使用SqlServer用户连接操作SqlServer数据库

网上下载SQLServer2022express版数据库,这里没啥可说的,随你喜欢,也可以下载Develop版本。安装完后,我们可以直接连接尝试, 不过一般来说,还是下载SQLServer管理工具来连接数据更加方便。 所以直接下载ssms, 我在用的时候,一开始只能用Windows身份登录。 所以首先,我…

前端数据模拟Mock.js

新建mock-demo的项目&#xff0c;安装npm install mockjs 新建index.js //引入mockjs import Mock from mockjs //设置延迟时间 // Mock.setup({ // timeout:4000 // }) //使用mockjs模拟数据 Mock.mock(/product/search,{"ret":0,"data":{"mtim…