C++11之右值引用
C++11之右值引用
传统的C++语法中就有引用的语法,而C++11中新增了的 右值引用(rvalue reference)语法特性,所以从现在开始我们之前学习的引用就叫做左值引用(lvalue reference)。无论左值引用还是右值引用,都是给对象取别名。
1. 左值和右值
C++的表达式要不然是右值(rvalue,读作“are-value”),要不然就是左值 (lvalue,读作“ell-value”)。这两个名词是从C语言继承过来的,原本是为了帮助记忆:左值可以位于赋值语句的左侧,右值则不能。但在C++语言中,二者的区别就没那么简单了。
- 左值:能对表达式取地址、或具名对象/变量。(如变量名或解引用的指针)
- 右值:不能对表达式取地址,或匿名对象。(如:字面常量、表达式返回值,函数返回值)
一般而言,一个左值表达式表示的是一个对象的身份,而一个右值表达式表示的是对象的值。
2. 左值持久;右值短暂
考察左值和右值表达式的列表,两者相互区别之处就很明显了:左值有持久的状态,而右值要么是字面常量,要么是在表达式求值过程中创建的临时对象。由于右值引用只能绑定到临时对象,我们得知:
- 所引用的对象将要被销毁
- 该对象没有其他用户
这两个特性意味着:使用右值引用的代码可以自由地接管所引用的对象的资源。
右值引用指向将要被销毁的对象。因此,我们可以从绑定到右值引用的对象 “窃取” 状态。
3. 变量是左值
变量可以看作只有一个运算对象而没有运算符的表达式,虽然我们很少这样看待变量。类似其他任何表达式,变量表达式也有左值/右值属性。变量表达式都是左值。带来的结果就是,我们不能将一个右值引用绑定到一个右值引用类型的变量上:
int &&rr1 = 42;//正确:字面常量是右值
int &&rr2 = rr1;//错误:表达式rr1是左值!
其实有了右值表示临时对象这一观察结果,变量是左值这一特性并不令人惊讶。毕竟,变量是持久的,直至离开作用域时才被销毁。
变量是左值,因此我们不能将一个右值引用直接绑定到一个变量上,即使这个变量是右值引用类型也不行。
4. 移动语义
4.1 移动构造
在模拟实现的string中增加移动构造,移动构造本质是将参数右值的资源窃取过来,占位已有,那么就不用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己。
// 移动构造
Janonez::string(string&& s):_str(nullptr),_size(0),_capacity(0)
{cout << "string(string&& s) -- 移动语义" << endl;swap(s);
}
Janonez::string to_string(int value)
{Janonez::string str;// ...return str;
}
int main()
{Janonez::string ret2 = Janonez::to_string(-1234);return 0;
}
再运行上面to_string的调用,我们会发现,这里没有调用深拷贝的拷贝构造,而是调用了移动构造,移动构造中没有新开空间,拷贝数据,所以效率提高了。
4.2 移动赋值
不仅仅有移动构造,还有移动赋值:在Janonez::string类中增加移动赋值函数,再去调用Janonez::to_string(1234),不过这次是将
Janonez::to_string(1234)返回的右值对象赋值给ret1对象,这时调用的是移动构造。
// 移动赋值
Janonez::string& operator=(string&& s)
{cout << "string& operator=(string&& s) -- 移动语义" << endl;swap(s);return *this;
}
int main()
{Janonez::string ret1;ret1 = Janonez::to_string(1234);return 0;
}
4.3 标准库move函数
虽然不能将一个右值引用直接绑定到一个左值上,但我们可以显式地将一个左值转换为对应的右值引用类型。我们还可以通过调用一个名为 move 的新标准库函数来获得绑定到左值上的右值引用,此函数定义在头文件<utility>中。move函数返回给定对象的右值引用。
int &&rr3 = std::move(rr1); // ok
move 调用告诉编译器:我们有一个左值,但我们希望像一个右值一样处理它。调用 move 就意味:除了对 rr1 赋值或销毁它外,我们将不再使用它。
我们可以销毁一个移后源对象,也可以赋予它新值,但不能使用一个移后源对象的值。
5. 万能引用(T&&)和引用折叠
-
T&&的两种含义
- 右值引用:当T是确定的类型时,T&&为右值引用。
- 当T存在类型推导时,T&&为万能引用,表示一个未定的引用类型。如果被右值初始化,则T&&为右值引用。如果被左值初始化,则T&&为左值引用。
-
引用折叠
-
由于引用本身不是一个对象,C++标准不允许直接定义引用的引用。
-
当类型推导时可能会间接地创建引用的引用,此时必须进行引用折叠。具体折叠规则如下:
(1)凡是有左值引用参与的情况下,最终的类型都会变成左值引用。
A& &、A& &&和A&& &都折叠成类型A&。(2)只有全部为右值引用的情况才会折叠为右值引用。类型
A&& &&折叠成A&&。
-
6. 完美转发
看下面示例代码,按我们的理解传入不同属性的对象,会调用不同的fun函数,但实际却并不是这样。
void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }template<typename T>
void PerfectForward(T&& t)
{Fun(t);
}
int main()
{PerfectForward(10); // 右值int a;PerfectForward(a); // 左值PerfectForward(std::move(a)); // 右值const int b = 8;PerfectForward(b); // const 左值PerfectForward(std::move(b)); // const 右值return 0;
}
运行结果:

我们发现打印结果全都是左值,这和我们预期是不同的,这是因为对象在传递过程中会将它的右值属性转换为左值属性,这样才能转移资源,那么我们想让对象在传递过程中保持它的左值或者右值的属性, 就需要用到完美转发。std::forward 完美转发在传参的过程中保留对象原生类型属性。
void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }template<typename T>
void PerfectForward(T&& t)
{Fun(std::forward<T>(t));
}int main()
{PerfectForward(10); // 右值int a;PerfectForward(a); // 左值PerfectForward(std::move(a)); // 右值const int b = 8;PerfectForward(b); // const 左值PerfectForward(std::move(b)); // const 右值return 0;
}
运行结果:

相关文章:
C++11之右值引用
C11之右值引用 传统的C语法中就有引用的语法,而C11中新增了的 右值引用(rvalue reference)语法特性,所以从现在开始我们之前学习的引用就叫做左值引用(lvalue reference)。无论左值引用还是右值引用&#…...
【PHP的设计模式】
PHP的设计模式 一、策略模式二、工厂模式三、单例模式四、注册模式五、适配器模式六、观察者模式 一、策略模式 策略模式是对象的行为模式,用意是对一组算法的封装。动态的选择需要的算法并使用。 策略模式指的是程序中涉及决策控制的一种模式。策略模式功能非常强…...
React 之 Redux - 状态管理
一、前言 1. 纯函数 函数式编程中有一个非常重要的概念叫纯函数,JavaScript符合函数式编程的范式,所以也有纯函数的概念 确定的输入,一定会产生确定的输出 函数在执行过程中,不能产生副作用 2. 副作用 表示在执行一个函数时&a…...
集合转数组
首先,我们在看到集合转数组的时候可能第一个想到的就是toArray(),但是我们在调用 toArray()的时候,可能会遇到异常 java.lang.ClassCastException;这是因为 toArray()方法返回的类型是 Obejct[],如果我们将其转换成其他类型&#…...
使用Python将Word文档转换为PDF的方法
摘要: 文介绍了如何使用Python编程语言将Word文档转换为PDF格式的方法。我们将使用python-docx和pywin32库来实现这个功能,这些库提供了与Microsoft Word应用程序的交互能力。 正文: 在现实生活和工作中,我们可能会遇到将Word文…...
Java 判断一个字符串在另一个字符串中出现的次数
1.split实现 package com.jiayou.peis.official.account.biz.utils;public class Test {public static void main(String[] args) {String k"0110110100100010101111100101011001101110111111000101101001100010101" "011101100101011010100011111010111001001…...
设计模式十三:代理(Proxy Pattern)
代理模式是一种结构型设计模式,它允许通过在对象和其真实服务之间添加一个代理对象来控制对该对象的访问。代理对象充当了客户端和真实服务对象之间的中介,并提供了额外的功能,如远程访问、延迟加载、访问控制等。 代理模式的使用场景包括&a…...
Redis基础 (三十八)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、概述 1.1 NoSQL 1.2 Redis 二、安装 2.1 安装方式 : 三、目录结构 3.1 rpm -ql redis 3.2 /etc/redis.conf 主配置文件 3.3 /var/lib/redis …...
maven中的scope
1、compile:默认值,可省略不写。此值表示该依赖需要参与到项目的编译、测试以及运行周期中,打包时也要包含进去。 2、test:该依赖仅仅参与测试相关的工作,包括测试代码的编译和执行,不会被打包,…...
【网络基础实战之路】实现RIP协议与OSPF协议间路由交流的实战详解
系列文章传送门: 【网络基础实战之路】设计网络划分的实战详解 【网络基础实战之路】一文弄懂TCP的三次握手与四次断开 【网络基础实战之路】基于MGRE多点协议的实战详解 【网络基础实战之路】基于OSPF协议建立两个MGRE网络的实验详解 PS:本要求基于…...
CNN(四):ResNet与DenseNet结合--DPN
🍨 本文为🔗365天深度学习训练营中的学习记录博客🍖 原作者:K同学啊|接辅导、项目定制 前面实现了ResNet和DenseNet的算法,了解了它们有各自的特点: ResNet:通过建立前面层与后面层之间的“短路…...
汽车EBSE测试流程分析(四):反思证据及当前问题解决
EBSE专题连载共分为“五个”篇章。此文为该连载系列的“第四”篇章,在之前的“篇章(三)”中已经结合具体研究实践阐述了“步骤二,通过系统调研确定改进方案”等内容。那么,在本篇章(四)中&#…...
如何在Spring MVC中使用@ControllerAdvice创建全局异常处理器
文章目录 前言一、认识注解:RestControllerAdvice和ExceptionHandler二、使用步骤1、封装统一返回结果类2、自定义异常类封装3、定义全局异常处理类4、测试 总结 前言 全局异常处理器是一种 🌟✨机制,用于处理应用程序中发生的异常ÿ…...
2023/08/05【网络课程总结】
1. 查看git拉取记录 git reflog --dateiso|grep pull2. TCP/IP和OSI七层参考模型 3. DNS域名解析 4. 预检请求OPTIONS 5. 渲染进程的回流(reflow)和重绘(repaint) 6. V8解析JavaScript 7. CDN负载均衡的简单理解 8. 重学Ajax 重学Ajax满神 9. 对于XML的理解 大白话叙述XML是…...
log_softmax比softmax更好?
多类别分类的一个trick 探讨一下在多类别分类场景,如翻译、生成、目标检测等场景下,使用log_softmax的效果优于softmax的原因。 假设词典大小为10,一个词的ID为9(即词典的最后一个词),使用交叉熵作为损失函…...
[LeetCode - Python]344.反转字符串(Easy);345. 反转字符串中的元音字母(Easy);977. 有序数组的平方(Easy)
1.题目 344.反转字符串(Easy) 1.代码 class Solution:def reverseString(self, s: List[str]) -> None:"""Do not return anything, modify s in-place instead."""# 双指针left,right 0, len(s)-1while left < right:temp s[left]s[…...
【SOP】最佳实践之 TiDB 业务写变慢分析
作者: 李文杰_Jellybean 原文来源: https://tidb.net/blog/d3d4465f 前言 在日常业务使用或运维管理 TiDB 的过程中,每个开发人员或数据库管理员都或多或少遇到过 SQL 变慢的问题。这类问题大部分情况下都具有一定的规律可循,…...
带有参数的 PL/SQL 过程/函数从选择查询返回表
技术标签: 【中文标题】带有参数的 PL/SQL 过程/函数从选择查询返回表【英文标题】:PL/SQL Procedure/function with params to return a table from(of) a select query【发布时间】:2020-12-01 11:17:49【问题描述】: 如何创建带参数的 (…...
文件的权限
1、修改文件的所属者和所属组 2、修改文件某一类人(所属者、所属组、其他人)的权限 一、用户对于普通文件的权限 二、用户对于目录文件的权限 三、访问控制列表ACL 四、特殊权限(了解) wuneng创建了几个文件,xiaoming对…...
vue3集成echarts最佳实践
安装 echarts npm install echarts --save 两种引用方式 非虚拟 dom import * as echarts from echarts;var chartDom document.getElementById(mychart); var myChart echarts.init(chartDom); var option;option {title: {text: Referer of a Website,subtext: Fake Da…...
AI时代测试人员如何转型
某老板:开发已经用AI提升了数倍的效率与产出,那测试呢?如果测试在AI时代掉队了,那是不是不需要测试了?某测试人员:我折腾了大半个月的AI,AI根本没办法给测试人员提效,它就像个弱智一…...
异常处理与性能调优:熬夜、加班与医美术后的“内服架构”实战指南
在互联网与高科技行业,系统的稳定运行往往伴随着开发者的极度透支。作为常年面对高并发需求和深夜发版的“IT 民工”或高压职场人,我们经常会遇到这样的尴尬场景:连续两周的 996 之后,面对电脑屏幕黑屏时的倒影,发现自…...
生产报工软件哪个好用?工厂扫码报工神器:企丰小工单详细介绍
现在很多中小型加工厂、五金机械、汽配、组装制造工厂,还在使用纸质单据手写报工。每天员工手写工单、文员加班录表、月底核算计件工资头疼不已。不仅工序混乱、产量统计不准,还容易出现虚报产量、工序漏报、薪资对账纠纷等问题。想要数字化管理…...
EPM900编程器HEX文件烧录指南与技巧
1. EPM900编程器与HEX文件烧录概述 EPM900是Keil公司推出的一款LPC系列微控制器仿真编程器,主要用于NXP LPC系列ARM芯片的调试与程序烧录。在实际工程开发中,我们经常需要将编译生成的HEX文件直接烧录到目标芯片中,而EPM900恰好支持这一功能。…...
Multi-Agent 系统故障排查:常见问题与解决方案速查手册
Multi-Agent系统故障排查实战手册:从踩坑到精通的全场景解决方案 关键词 多智能体系统、故障排查、分布式系统、Agent通信故障、共识算法、容错机制、可观测性 摘要 随着大模型技术的爆发,Multi-Agent(多智能体)系统已经成为AI应用、工业互联网、分布式机器人、智能客服…...
别再乱改usb_conf.h了!一文搞懂STM32 USB端点缓冲区PMA的分配原理
STM32 USB端点缓冲区PMA分配原理深度解析 第一次接触STM32 USB开发时,看到usb_conf.h里那些神秘的地址定义,你是否也曾一头雾水?为什么ENDP0_RXADDR有人设0x18,有人设0x40?这些数字背后隐藏着怎样的硬件机制࿱…...
实时商业情报不再滞后,Perplexity新闻搜索配置全拆解,从入门到日均处理200+信源
更多请点击: https://codechina.net 第一章:实时商业情报不再滞后,Perplexity新闻搜索配置全拆解,从入门到日均处理200信源 为什么传统RSS与Google Alerts已失效 现代商业情报对时效性、语义准确性与信源可信度提出更高要求。Pe…...
Teledyne PDS后处理软件保姆级教程:从新建项目到格网导出的完整流程
Teledyne PDS后处理软件从入门到精通:多波束数据处理全流程实战指南 第一次打开Teledyne PDS后处理软件时,满屏的专业术语和复杂菜单让不少水下测量工程师感到无从下手。作为处理T50P等多波束测深数据的核心工具,PDS软件的操作流程直接关系到…...
Boomi 与 Gong 达成合作,将 Revenue AI 引入 Boomi Agentstudio
Gong 的 Revenue AI 现已原生集成至 Boomi Enterprise Platform 面向 AI 时代的数据激活公司 Boomi 今日宣布,与 Revenue AI 领域领导者 Gong 达成合作,将 Gong 捕获的营收信号原生整合至 Boomi Enterprise Platform。通过此次合作,企业可构…...
Cadence Allegro 16.6 环境设置保姆级教程:从绘图参数到自动保存,新手避坑指南
Cadence Allegro 16.6 环境设置实战指南:从零配置到高效设计 第一次打开Cadence Allegro 16.6时,满屏的菜单选项和参数设置可能会让新手感到无所适从。作为一款专业的PCB设计工具,Allegro提供了高度可定制的工作环境,但这也意味着…...
