C++ 左值与右值浅谈

news2025/1/10 10:36:52

左值与右值

  • 序言
  • 概念
    • 左值和右值的划分理解
    • 右值引用
      • 常量左值引用与右值引用
    • 移动语义
    • 引用折叠
    • 完美转发
  • 参考资料

序言

虽然平常都算是了解左值,右值的用法,但是好记性不如烂笔头,记下来供大家评鉴,有错改错,有善赞善,也是对于自己知识的一次梳理。

为什么要分清楚左值和右值?这是因为在理清楚左值和右值,合适为其设置适合的用法,能够有效减少资源开销。

但是,对于一些POD类型的资源,那就无所谓左值右值了,因为拷贝即移动,移动即拷贝。

接下来我以左值和右值的讨论依次简单讲解:左值和右值的概念,右值引用,移动语义,引用折叠,完美转发。明确左值和右值理清楚后,可以使用的主要用法。

:1. 开始看下面之前,需要注意的是!这些除了专业名词之外,基本都是基于个人理解去通俗诠释概括的,想直接看专业且全面的概念就找末尾的参考资料看。
2.以下有比较多的专业词汇,初学者建议慢慢看查询拓展。

概念

左值和右值的划分理解

左值(lvalue)和右值(rvalue)是C++11之前的概念,但是也通用到后面。
C++11及之后,划分为 泛左值(glvalue)、将亡值(xvalue,也称亡值,消亡值)和纯右值(prvalue)

左值(C++11之前):赋值运算“=”左边的变量
右值(C++11之前):赋值运算“=”右边的表达式

左值(C++11及之后):非将亡值的泛左值,有地址的变量
右值(C++11及之后):纯右值或者将亡值,生命周期在表达式里。
int a = 15 + 29;
std::cout << &a;	// 0xeffc40
std::cout << &(15 + 29);	//error: Cannot take the address of an rvalue of type 'int'
std::cout << &"xzz";	//0xa16444

以简单的例子,这个a,承载类型的值,自身是有地址的,可以取地址值,这个就是左值。
15 + 29这个表达式的结果是纯右值,不能取地址值。

注:顺带一提,许多普通常量都是纯右值,但是字符串不是,是左值,因为普通常量都是可以用普通的机器码就可以表示其值,但是字符串无法合适表示,所以将其放置在常量区分配内存专门存放。

想必想了解左值和右值的人,估计都看过这个图:
在这里插入图片描述
或者是类似的,基本都是说将亡值泛左值右值的交集。

但是这其实是容易让人摸不着头脑的,但是本质角度上又是能说得过去的。

1. 将亡值被包含在右值这边,是因为其的    生命周期和右值是一样     的,都在一个表达式里面。
2. 将亡值被包含在泛左值这边,是因为其是      匿名对象,有地址,和左值是一样     的。

而上述也引申出了怎么判断将亡值。

将亡值:生命周期在一个表达式里,且是匿名对象有地址。

C++17的临时量实质化也是将亡值。

.

右值引用

右值引用T &&),顾名思义是引用右值的,无论是纯右值还是将亡值

右值引用是C++11引入的,值得注意的是右值引用的变量是个左值

因为其是完全符合左值定义的,众所周知,引用本质上是一种特殊的指针,可以这么认为,指针指向的值是右值,但是指针本身并不是右值。

所以你如果想右值引用 右值引用的变量 这样是不行的:

int &&a = 5;	// 编译正常,可以随意右值引用纯右值
int &&b = a;   	// 编译错误

右值引用的目的是延长将亡值的生命周期,减少资源开销,或者是为了移动语义服务,使其进行资源转移。

struct AA {};
AA createAA() {
	return AA();
}
int main() {
	AA &&a = createAA(); 
}

右值引用AA &&a接纳了本来表达式结束就要释放掉资源的匿名对象AA()

并可以任意更改匿名对象的资源。

常量左值引用与右值引用

在C++11之前,负责右值引用(T &&)功能的是常量左值引用(const T &),只不过和右值引用相比,常量左值引用无法修改其值,且只能用于拷贝语义不能用以移动语义
在这里插入图片描述
在这里插入图片描述
可以看出来,常量左值引用右值引用做的事情是一样的。

顺带一提,不建议用右值引用去引用POD类型的纯右值,因为纯右值要想被右值引用,就得先压栈地址,才能给其引用。

从开销上看,不如直接普通的赋值
在这里插入图片描述
在这里插入图片描述
就算单纯只看条数,右值引用用了3条,普通赋值才用了1条,开销一目了然。

.

移动语义

移动语义(Move Semantics)是 C++11 引入的一项重要特性,它使得实例对象的资源不通过拷贝的方式进行转移(除了POD类型)。

移动语义具体化其实就是移动构造函数。

struct Resource { ... }

class XZZ 
{
public:
	...
	构造或者其他的实例化资源
	...
	移动构造函数
	XZZ(XZZ &&value) {
		this.m_resource = value.m_resource;
		value.m_resource = nullptr;
	}
	/// 移动赋值函数
	XZZ &operator =(XZZ &&value) {
		this.m_resource = value.m_resource;
		value.m_resource = nullptr;
	}
	...
private:
	Resource *m_resource = nullptr;
}

上面是个简单的例子,主要是为了理解移动是怎么来移动资源的。

如果m_resource不是指针,也可以通过使用std::move强行将value.m_resource转成右值来触发this.m_resource的移动构造,使得两个m_resource的资源进行移动达到同样的效果。

_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept {
    return static_cast<remove_reference_t<_Ty>&&>(_Arg);
}

std::move的效果便是强制将传进来的参数转成右值,一般可以将已经右值引用的变量或者将要释放的类型转成右值(将亡值),实现移动语义的功能。

再次提醒,如果资源是POD类型的,那用移动语义其实没有意义,因为移动就是拷贝,拷贝就是移动。

另外移动构造什么情况下可以编辑器会提供默认移动构造,什么情况下会弃置默认移动构造只能自己写的,这些内容不在本节重点,感兴趣可自行查看。
.

引用折叠

说回右值引用的类型,左值引用右值引用,或者右值引用左值引用,那到底是左值引用还是右值引用呢?

C++11中引入引用折叠规则(reference collapsing),通过模板或 typedef 中的类型操作可以构成引用的引用,此时适用引用折叠规则:右值引用的右值引用折叠成右值引用,所有其他组合均折叠成左值引用

废话不多说:
C++ 11新特性解析与应用
简单通俗来说,只有右值引用本身,和叠加两次的右值引用,类型才是右值引用类型,否则,含至少一个引用&的都是左值引用

不能直接声明一个超过两个&的类型

int a = 10;
int &&& b = a;	// error: 'b' declared as a reference to a reference

但是如果通过using或者typedef间接声明就可以了

typedef int& intR;
using intRe = int&;

int a = 10;
intR && b = a;		// 等同于 int &b = a
intRe && c = a;		// 等同于 int &c = a

有了引用折叠,就可以好好使用类型擦除完美转发参数类型给别的函数或者类。
.

完美转发

所谓完美转发(prefect forwarding),是指在函数模板中,完全依照模板的参数的类型,将参数传递给函数模板中调用的另外一个函数。 ——《C++ 11新特性解析与应用》

完美转发关键点在于:

  1. 函数模板
  2. 函数模板参数类型是 类型&&
  3. 要接收函数模板参数的函数/类,实参用std::forward包装一下
template <typename _Ty, typename... _Type>
_Ty *createClass(_Type&&... args) {
    return new _Ty(std::forward(args)...);
}

这是个没什么实质意义的模板函数,仅是为了举例。

为什么要用std::forward

是因为右值引用args本身是左值,传进来本身如果是个右值的话,结果给到接收函数是个左值,那就不是“完美”转发了。

_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept {
    return static_cast<_Ty&&>(_Arg);
}

_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr _Ty&& forward(remove_reference_t<_Ty>&& _Arg) noexcept {
    static_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");
    return static_cast<_Ty&&>(_Arg);
}

所以需要转成右值的类型,而如果是左值的话,因为函数重载引用折叠的缘故,即使通过std::forward也是转成左值类型。

参考资料

《C++ 11新特性解析与应用》
《C/C++ 参考文档》

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

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

相关文章

Jmeter接口测试之常用断言

在接口测试中&#xff0c;我们需要检查请求处理结果是否正确。当请求的响应状态码为200&#xff0c;是否表时接口功能正常呢&#xff1f;显然是不正确的。 响应状态为200&#xff0c;只能表明服务处理了你的请求&#xff0c;同时进行了结果返回&#xff1b;但并不能代表处理的…

机器学习--卷积神经网络(包括python实现)

卷积神经网络 1. 计算方法 &#xff08;1&#xff09;输入和输出channel 1时 首先我们要知道channel是什么意思&#xff0c;顾名思义channel就是“通道”的意思qwq。我们来举个例子&#xff0c;在计算机视觉中&#xff0c;如果一张图片是黑白的&#xff0c;那么每个像素点都…

微信小程序页面制作——婚礼邀请函(含代码)

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

windows下ardusub仿真

接上篇&#xff1a;windows编译ardupilot源码教程 执行以下命令。 #在ardusub根目录下执行下面命令 cd ./Tools/autotest./waf configure --debugpython sim_vehicle.py -v ArduCopter -f quad --console --map -D -L RATBeach 编译时间较长&#xff0c;之后会打开三个窗口。 …

SpringBoot 整合酷狗获取下载音乐(需要自己账户)

程序员必备宝典https://tmxkj.top/#/ 在此声明,本内容仅供个人学习、研究或娱乐之用,严禁任何形式的商业用途。若您发现本内容被用于商业目的,请立即与我们联系,我们将删除原代码。 我们尊重并保护所有原创作品的知识产权。 为了营造一个健康、积极的网络环境,我们鼓励用户…

故障诊断迁移学习项目DDC(保姆教程)

本项目从零开始搭建深度领域混淆&#xff08;Deep Domain Confusion&#xff0c;DDC&#xff09;算法。项目包括加载CWRU轴承原始信号&#xff0c;信号处理、数据集制作&#xff0c;模型搭建&#xff0c;DDC域混淆算法设计、特征可视化&#xff0c;混淆矩阵等流程来帮助读者学习…

Qt_了解Qt Creator

目录 1、使用Qt Creator新建项目 1.1 新建项目 1.2 选择项目模板 1.3 选择项目路径 1.4 选择构建系统 1.5 填写类信息 1.6 选择语言翻译文件 1.7 选择编译器 1.8 选择版本控件系统 1.9 最终效果 2、代码解析 2.1 main.cpp 2.2 widget.h 2.3 widget.cpp …

[SDK] -模态对话框 和 非模态对话框

前言 各位师傅大家好&#xff0c;我是qmx_07&#xff0c;今天给大家讲解对话框的相关知识点&#xff0c;就此SDK学习告一段落&#xff0c;之后会更新相关项目内容 创建对话框 项目->添加 ->资源->Dialog->修改对话框ID->拖拉尺寸设置对话框大小 通过菜单绑定…

多通道电源测试设备怎么测试多路电源?

为了提升多路电源模块的测试效率和精度&#xff0c;NSAT-8000多通道ATE自动化测试设备持续迭代创新&#xff0c;旨在精准检测电源每个通道的性能指标&#xff0c;判断电源质量是否合格。 一、测试系统结构 二、测试设备 常用的测试电源的仪器主要有示波器、数字万用表、电子负载…

Android app广告变现广告预算来源有哪些?

APP开发者想要通过广告变现实现收益的最大化&#xff0c;首先要了解广告预算来源有哪些&#xff1f; 1、Push 推送广告 通过推送消息到用户设备通知栏上展示广告。 2、第三方 SDK 广告 很多应用都会集成第三方广告平台&#xff0c;比如 AdMob、Facebook Audience Network、…

ESP32-S3百度文心一言大模型AI语音聊天助手(支持自定义唤醒词训练)【手把手非常详细】【万字教程】

简介 此项目主要使用ESP32-S3实现一个AI语音聊天助手&#xff0c;可以通过该项目熟悉ESP32-S3 arduino的开发&#xff0c;百度语音识别&#xff0c;语音合成API调用&#xff0c;百度文心一言大模型API的调用方法&#xff0c;音频的录制及播放&#xff0c;SD卡的读写&#xff0c…

SAP自建表log功能开启

1、SE11下进入“技术设置”&#xff0c;勾选“日志更改” 2、RZ10修改系统参数 rec/clientALL, 或rec/client000&#xff08;客户端号&#xff0c;多个客户端使用“&#xff0c;”分割。激活参数文件 没有这个参数的话新增一个 修改了SAP系统参数文件DEFAULT.PFL需要重启SAP…

【ESP-IDF FreeRTOS】软件定时器

除了ESP-IDF中的软硬件定时器&#xff0c;我们还可以使用FreeRTOS中的软件定时器&#xff0c;它是基于Tick的定时器。不过我一般不用&#xff0c;因为有ESP-IDF的定时器了嘛&#xff0c;但还是介绍一下。 首先包含头文件。 #include "freertos/timers.h" 接着我们…

N2011A叉车限速器如何实现超速报警且强制限速的

叉车安装限速器是对厂区叉车控制行驶速度常见的一种方式&#xff0c;但限速器真的能限速吗&#xff1f; 九盾N2011A叉车限速器是采取无线传感器的方式&#xff0c;相比传统的限速器&#xff0c;需要前桥打孔攻牙&#xff0c;稍有不慎就打断&#xff0c;安装麻烦耗工时&#xf…

2024年提升转化率的10个最佳弹窗软件解决方案

无论你是喜欢还是讨厌它们&#xff0c;弹窗通知并不一定都是坏的。当然&#xff0c;大多数网站访问者并不愿意被横幅打扰&#xff08;更糟糕的是那种自动播放音频的视频&#xff09;。不过&#xff0c;你有没有想过只在他们快要离开你的网站时才显示弹窗&#xff1f;使用退出意…

FP7127 / FP7128:LED舞台灯降压方案 RGB调光 智能调光模块

前言&#xff1a; 舞台灯作为一种应用于文化娱乐场所的灯具&#xff0c;用来营造环境、渲染氛围&#xff0c;在舞台上突出中心人物、塑造演员形象&#xff0c;在文化场馆&#xff0c;如博物馆等的场所&#xff0c;突出展品细节。根据灯光用途和适用类型&#xff0c;舞台灯可以…

【F的领地】项目拆解:百家号批量搬运掘金 | 搬运类项目核心思路分享

【F的领地】项目拆解&#xff1a;百家号批量搬运掘金 项目介绍 百家号批量搬运掘金是之前老百家号项目的一种新玩法&#xff0c;操作简单。 只需会操作电脑和手机即可&#xff0c;无脑搬运就行&#xff0c;玩法是批量搬运视频&#xff0c;用软件去重后在百家号发布。 然后是…

Miracast/WifiDisplay开发相关的深入调研分析-android投屏实战开发

Miracast/WifiDisplay概念介绍 Miracast Miracast是由Wi-Fi联盟于2012年所制定&#xff0c;以Wi-Fi直连&#xff08;Wi-Fi Direct&#xff09;为基础的无线显示标准。支持此标准的消费性电子产品&#xff08;又称3C设备&#xff09;可透过无线方式分享视频画面&#xff0c;例如…

Linux和C语言(Day09)

一、学习内容 指针 指针的概念 什么是内存 内存是计算必不可少的硬件设备&#xff0c;一般说到内存常会说TA多大——M、G、T 内存单位&#xff1a;bit【位&#xff0c;最小单位】 Byte【字节&#xff0c;基本单位】 KB MB GB TB CPU如何从内存取数据 通过内存地址去取 将内存…

全球主流单片机制造商

欧美地区 1、FreescaleNXP&#xff08;飞思卡尔恩智浦&#xff09;&#xff1a;荷兰&#xff0c;主要提供16位、32位MCU。应用范围&#xff1a;汽车电子、LED和普通照明、医疗保健、多媒体融合、家电和电动工具、楼宇自动化技术电机控制、电源和功率转换器、能源和智能电网、自…