左右值引用和移动语义
文章首发公众号:iDoitnow
1. 左右值和左右值引用
什么是左值、右值呢?一种极不严谨的理解为:在赋值的时候,能够被放到等号左边的值为左值,放在右边的值为右值。例如:
int sum(int x, int y){return x + y;}int a = 1; //a为左值,常数1为右值
int b = a + a; //b为左值,表达式a+a为右值
int c = sum(a, a);//c为左值,但函数sum(a, a)返回值为右值
通过上面的例子,常数a、表达式(a+a)和函数sum(a+a)返回值他们都是临时值,这些值都保存在寄存器中,无法取到他们的地址;而对于a、b和c为具体的变量名,存储在内存中,可以取到其地址。因此一般情况下可以根据能否取到地址,来区分左值和右值。
在了解左值和右值之前,我们首先要知道表达式的概念:由运算符和运算对象构成的计算式(类似数学中的算术表达式)。表达式是可以求值的,因此根据表达式值的类别,可以对其进行分类(准确的来说,是表达式的结果的值类别,但我们一般不刻意区分表达式和表达式的求值结果,所以这里称“表达式的值类别”。),C++11之后将表达式定义了五种类型:
-
lvalue(Left-hand-side value,左值)
-
prvalue(Pure rvalue,纯右值)
-
xvalue(eXpiring value,将亡值)
-
rvalue(Right-hand-side value,右值)
-
glvalue(Generalized lvalue,泛左值)
它们之间的关系如下图所示:
C++11中将表达式按值类别可以分为左值、将亡值和纯右值。其中,左值和将亡值合称为泛左值,纯右值和将亡值合称为右值。
随着移动语义(后面我们会详细介绍)引入到 C++11 之中,值类别被重新进行了定义,C++之父Bjarne Stroustrup在《“New” Value Terminology》中给出以区别表达式的两种独立的性质:
- 拥有身份 (identity):可以确定表达式是否与另一表达式指代同一实体,例如通过比较它们所标识的对象或函数的(直接或间接获得的)地址;
- 可被移动:移动构造函数、移动赋值运算符或实现了移动语义的其他函数重载能够绑定于这个表达式。
C++11 中:
- 拥有身份且不可被移动的表达式被称作左值(lvalue)表达式;
- 拥有身份且可被移动的表达式被称作将亡值 (xvalue)表达式;
- 不拥有身份且可被移动的表达式被称作纯右值 (prvalue)表达式;
1.1 左值
一般情况下,左值我们可以简单地理解理解为:能够使用&取地址的表达式。
常见的左值有:
- 变量名
- 函数名
- 返回左值引用的函数调用
- 前置自增/减的运算符链接的表达式(如
++i/--i) - 内置的赋值表达式(如
a=b,a+=1) - 字符串等。
【注:字符串是可以取地址的,因此字符串常量也属于左值】
1.2 纯右值
纯右值:表达式本身就是纯粹的字面值(如1,ture,1.0);或者,该表达式求值结果相当于一个字面值或一个不具名的临时对象。
常见的纯右值有:
- 除字符串字面值以外的字面值
- 返回非引用类型的函数调用
- 后置自增/减的运算符链接的表达式(如
i++/i--) - 算术/逻辑/比较表达式(如
a+b,a&&b,a==b) - 取地址表达式(如
&a)
1.3 将亡值
将亡值是在C++11中引进来的,顾名思义,就即将销毁的东西。将亡值的产生与右值引用的产生而引起的,对于将亡值我们常用到的有:
- 返回类型是右值引用的函数调用或重载运算符的表达式(如
std::move(x)) - 转换为右值引用的转换函数的调用表达式(如
static<int&&>(a))
1.4 左右值引用
左值引用就是对左值的引用。它的形式如:T&,根据const属性可以分为两种:
- const左值引用
- 非const左值引用
例如:
int a = 1;
int& la = a;//la为a的左值引用(非const左值引用)
la = 2;//la为非const左值引用,可以修改它的值const int& c_la = a;//c_la为a的左值引用(const左值引用)
c_la = 2;//该语法错误,c_la为const左值引用,不可以修改它的值
右值引用就是对右值的引用,通过T&&来表示。右值的引用只能绑定到右值上。
2. 移动语义
在未出现右值引用之前,我们在函数调用传参的时候,在某些时候可以使用按引用传递参数,减少参数多的拷贝对资源的消耗,提高程序的运行效率。当我们在处理包含大量数据的对象时,移动语义显的尤为重要。
2.1 std::move
如何将一个左值转换为一个右值呢?C++11在头文件utility中声明了std::move()函数,该函数的作用就是类型转换,通过它,我们可以 把一个左值,将其标记为右值。move()不做任何资源转移的操作,只是产生一个将亡值表达式来标识参数x,其完全等同于static_cast<T&&>(x)。例如:
int a = 1;
int&& r_a = a; //错误,右值引用只能绑定到右值上,而a是一个左值
int&& r_a = std::move(b); //正确, std::move(a) 是一个右值,可以用右值引用绑定
2.2 移动构造函数
一个类 T 的首个形参是 T&&、const T&&、volatile T&& 或 const volatile T&&,且没有其他形参,或剩余形参都有默认值。
具体的形式如下:
T (T &&) //移动构造函数的典型声明形式
T (T &&) = default; //强制编译器生成移动构造函数。
T (T &&) = delete; //避免隐式生成移动构造函数。
示例:
#include <string>
#include <iostream>
#include <utility>class A
{private:std::string s;public:A(std::string str = "A()") : s(str) {std::cout<<s<<"的构造函数\n";}A(A&& o) : s(std::move(o.s)) {std::cout<<s<<"的移动构造函数\n";}~A(){std::cout<<s<<"的析构函数\n";}
};A f(A a) { return a; }int main()
{A a1(f(A("a")));// 按值返回时,从函数形参移动构造它的目标A a2(std::move(a1));// 从亡值移动构造
}
2.3 移动赋值运算符
一个类 T 的移动赋值运算符是名为 operator=的非模板非静态成员函数,它接受恰好一个 T&&、const T&&、volatile T&& 或 const volatile T&& 类型的形参。
具体的形式如下:
T & T ::operator= (T &&) //移动赋值运算符的典型声明
T & T ::operator= (T &&) = default; //强制编译器生成移动赋值运算符
T & T ::operator= (T &&) = delete; //避免隐式移动赋值
示例:
#include <string>
#include <iostream>
#include <utility>class A
{private:std::string s;public:A(std::string str = "A()") : s(str) {std::cout<<s<<"的构造函数\n";}~A(){std::cout<<s<<"的析构函数\n";}A& operator=(const A& other){s = other.s;std::cout << "复制赋值\n";return *this;}A& operator=(A&& other){s = std::move(other.s);std::cout << "移动赋值\n";return *this;}
};A f(A a) { return a; }int main()
{A a1("a1"), a2("a2");std::cout << "尝试从右值临时量移动赋值 A\n";a1 = f(A("a")); // 从右值临时量移动赋值std::cout << "尝试从亡值移动赋值 A\n";a2 = std::move(a1); // 从将亡值移动赋值
}
参考文献
C++ Primer Plus(第六版) - 第18章 探讨C++新标准
C++ 参考手册
相关文章:
左右值引用和移动语义
文章首发公众号:iDoitnow 1. 左右值和左右值引用 什么是左值、右值呢?一种极不严谨的理解为:在赋值的时候,能够被放到等号左边的值为左值,放在右边的值为右值。例如: int sum(int x, int y){return x y;…...
一起学习用Verilog在FPGA上实现CNN----(七)全连接层设计
1 全连接层设计 1.1 Layer 进行线性计算的单元layer,原理图如图所示: 1.2 processingElement Layer中的线性计算单元processingElement,原理图如图所示: processingElement模块展开原理图,如图所示,包含…...
tomcat打debug断点调试
windows debug调试 jdk版本:1.8.0_181 tomcat版本:apache-tomcat-9.0.68.0 idea版本:2020.1 方法一 修改catalina.bat 在%CATALINA_HOME%\bin\catalina.bat中找到 set “JAVA_OPTS%JAVA_OPTS% -Djava.protocol.handler.pkgsorg.apache…...
如果持有互斥锁的线程没有解锁退出了,该如何处理?
文章目录如果持有互斥锁的线程没有解锁退出了,该如何处理?问题引入PTHREAD_MUTEX_ROBUST 和 pthread_mutex_consistent登场了结论:如果持有互斥锁的线程没有解锁退出了,该如何处理? 问题引入 看下面一段代码…...
信息论绪论
本专栏针包含信息论与编码的核心知识,按知识点组织,可作为教学或学习的参考。markdown版本已归档至【Github仓库:information-theory】,需要的朋友们自取。或者关注公众号【AIShareLab】,回复 信息论 也可获取。 文章目…...
Buffer Status Reporting(BSR)
欢迎关注同名微信公众号“modem协议笔记”。 以一个实网中的异常场景开始,大概流程是有UL data要发送,UE触发BSR->no UL grant->SR->no UL grant->trigger RACH->RACH fail->RLF->RRC reestablishment:简单描述就是UE触…...
代码随想录LeetCode | 单调栈问题
前沿:撰写博客的目的是为了再刷时回顾和进一步完善,其次才是以教为学,所以如果有些博客写的较简陋,是为了保持进度不得已而为之,还请大家多多见谅。 预:看到题目后的思路和实现的代码。 见:参考…...
C++之可调用对象、bind绑定器和function包装器
可调用对象在C中,可以像函数一样调用的有:普通函数、类的静态成员函数、仿函数、lambda函数、类的非静态成员函数、可被转换为函数的类的对象,统称可调用对象或函数对象。可调用对象有类型,可以用指针存储它们的地址,可…...
MongoDB--》文档查询的详细具体操作
目录 统计查询 分页列表查询 排序查询 正则的复杂条件查询 比较查询 包含查询 条件连接查询 统计查询 统计查询使用count()方法,其语法格式如下: db.collection.count(query,options) ParameterTypeDescriptionquerydocument查询选择条件optio…...
网络协议(六):网络层
网络协议系列文章 网络协议(一):基本概念、计算机之间的连接方式 网络协议(二):MAC地址、IP地址、子网掩码、子网和超网 网络协议(三):路由器原理及数据包传输过程 网络协议(四):网络分类、ISP、上网方式、公网私网、NAT 网络…...
热启动预示生态起航的Smart Finance,与深度赋能的SMART通证
2023年初加密市场的回暖,意味着各个赛道都将在新的一年里走向新的叙事。最近,我们看到GameFi赛道也在市场回暖的背景下,逐渐走出阴霾。从融资数据上看,1月获得融资的GameFi项目共12个,融资突破8000万美元,1…...
提分必练,中创教育PMP全真模拟题分享
湖南中创教育每日五题分享来啦,“日日行,不怕千万里;常常做,不怕千万事。”,每日五题我们练起来! 1、在系统测试期间,按已识别原因的类型或类别记录了失败测试的数量。项目经理首先需要从最大故…...
PID控制算法基础介绍
PID控制的概念 生活中的一些小电器,比如恒温热水器、平衡车,无人机的飞行姿态和飞行速度控制,自动驾驶等等,都有应用到 PID——PID 控制在自动控制原理中是一套比较经典的算法。 为什么需要 PID 控制器呢? 你一定用…...
Ajax 学习笔记
一、Ajax1.1 什么是AjaxAJAX Asynchronous JavaScript and XML(异步的JavaScript和XML)。Ajax是一种在无需加载整个网页的情况下,能够更新部分网页的技术,它不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术…...
力扣解法汇总1234. 替换子串得到平衡字符串
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 有一个只含有 Q, W, E, R 四种字符,且长度为 n 的字符串。 假如在该…...
C++关键字之const、inline、static
C 关键字总结 1.const const是 constant 的缩写,本意是不变的、不易改变的意思。在C中用来修饰内置类型变量,自定义对象,成员函数,返回值,函数参数使用如下: //修饰普通类型变量 const int a 7; int ba;…...
【成为架构师课程系列】怎样进行概念架构(Conceptual Architecture)?
目录 前言 什么是概念架构 概念架构阶段的3个步骤 初步设计 高层分割 分层式概念服务架构 Layer:逻辑层 Tier: 物理层 按通用性分层 技术堆叠 考虑非功能需求 【禅与计算机程序设计艺术:更多阅读】 前言 胜兵先胜而后求战,败兵先站而后求胜。…...
PostgreSQL的下载安装教程(macOS、Windows)
postgresql是GIS服务端几乎不可避免要打交道的数据库。因为mysql的空间扩展真是不尽人意。所以想要学会GIS服务端知识,postgresql(下文简称pg)你是必须要会的。 首先要知道,pg是一个空间数据库,和普通数据库不同的是pg支持空间数据的存储与操作。这里所谓的空间数据一般指…...
98年的确实卷,公司新来的卷王,我们这帮老油条真干不过.....
都说00后躺平了,但是有一说一,该卷的还是卷。这不,前段时间我们公司来了个00后,工作没两年,跳槽到我们公司起薪18K,都快接近我了。后来才知道人家是个卷王,从早干到晚就差搬张床到工位睡觉了。 …...
软件架构知识2-系统复杂度
架构设计的真正目的:是为了解决软件系统复杂度带来的问题,一个解决方案。 系统复杂度,如何入手: 1、通过熟悉和理解需求,识别系统复杂性所在的地方,然后针对这些复杂点进行架构设计。 2、架构设计并不是要…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...
P10909 [蓝桥杯 2024 国 B] 立定跳远
# P10909 [蓝桥杯 2024 国 B] 立定跳远 ## 题目描述 在运动会上,小明从数轴的原点开始向正方向立定跳远。项目设置了 $n$ 个检查点 $a_1, a_2, \cdots , a_n$ 且 $a_i \ge a_{i−1} > 0$。小明必须先后跳跃到每个检查点上且只能跳跃到检查点上。同时࿰…...
联邦学习带宽资源分配
带宽资源分配是指在网络中如何合理分配有限的带宽资源,以满足各个通信任务和用户的需求,尤其是在多用户共享带宽的情况下,如何确保各个设备或用户的通信需求得到高效且公平的满足。带宽是网络中的一个重要资源,通常指的是单位时间…...
