右值引用和移动语义以及C++11新增的类功能

正文开始前给大家推荐个网站,前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。

右值引用和左值引用

传统的C++语法中就有引用的语法,而C++11中新增了的右值引用语法特性,无论左值引用还是右值引用,都是给对象取别名。
什么是左值?什么是左值引用?
左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。

int main()
{
	// 以下的p、b、c、*p都是左值
	int* p = new int(0);
	int b = 1;
	const int c = 2;
	// 以下几个是对上面左值的左值引用
	int*& rp = p;
	int& rb = b;
	const int& rc = c;
	int& pvalue = *p;

	delete p;
	return 0;
}

什么是右值?什么是右值引用?
右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。右值引用就是对右值的引用,给右值取别名。

int main()
{
	double x = 1.1, y = 2.2;
	// 以下几个都是常见的右值
	10;
	x + y;
	fmin(x, y);
	// 以下几个都是对右值的右值引用
	int&& rr1 = 10;
	double&& rr2 = x + y;
	double&& rr3 = fmin(x, y);
	// 这里编译会报错:error C2106: “=”: 左操作数必须为左值
	//10 = 1;
	//x + y = 1;
	//fmin(x, y) = 1;
	return 0;
}

对于内置类型的右值我们称为纯右值,对于自定义类型的右值,它没有字面常量,和表达式,一般是函数的返回值,我们称为将亡值。
需要注意的是右值是不能取地址的,但是给右值取别名后,会导致右值被存储到特定位置,且可以取到该位置的地址,也就是说例如:不能取字面量10的地址,但是rr1引用后,可以对rr1取地址,也可以修改rr1。如果不想rr1被修改,可以用const int&& rr1 去引用,可以理解为右值被右值引用 引用以后它的属性就变成了左值。

左值引用和右值引用的比较
左值引用

  1. 左值引用只能引用左值,不能引用右值。
  2. 但是const左值引用既可引用左值,也可引用右值。

右值引用

  1. 右值引用只能右值,不能引用左值。
  2. 但是右值引用可以move以后的左值。

move可以改变变量的属性,可以将左值变为右值,但是变量本身的属性不会变,他是一个传值返回。当需要用右值引用引用一个左值时,可以通过move函数将左值转化为右值。

那么右值引用有什么用呢???

我们只到左值引用做参数和做返回值都可以提高效率。减少拷贝,但是当返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回,只能传值返回。如果返回的对象是一个内置类型,那消耗也不大,但是如果是一个深拷贝的对象,比如说string。

string tostring(int s)
{
	string ret;

	while (s)
	{
		ret += (s % 10) + '0';
		s /= 10;
	}
	reverse(ret.begin(), ret.end());
	return ret;
}

这种情况下是无法使用左值引用返回的。因为出了作用域ret就会销毁。但是如果使用传值返回,一定会面临深拷贝的问题,消耗太大。
在这里插入图片描述
使用传值返回将会面临2次深拷贝和两次析构,消耗很大。我们想一下,ret指向的资源是出了作用域就要销毁的值,但是他指向的空间是我们需要的,我们可不可以把它指向的空间交换出来,是不是就可以减少拷贝了。

在这里插入图片描述
像ret这种的将亡值,就是我们所说的右值,所以我们可以写一个右值的拷贝构造函数,也就是移动构造,我们可以把即将销毁的值转移出来,从而达到减少拷贝的作用。移动构造中没有新开空间,拷贝数据,所以效率提高了。

string(string&& s)
 :_str(nullptr)
 ,_size(0)
 ,_capacity(0)
{
	 swap(s);
}

有了移动构造以后,当发生这种右值拷贝拷贝时就能减少一次深拷贝,提升还是很大的,但是拷贝完以后,这个临时对象也是一个右值,要用它去赋值给s,所以和上面同理,我们还需要一个移动赋值。

// 移动赋值
string& operator=(string&& s)
{
	swap(s);
	return *this;
}

如果我们写了移动构造又写了拷贝构造,编译器会选择最合适的调用,如果拷贝的对象是右值,那么就会调用移动构造,左值就会调用拷贝构造,如果我们不写移动构造,那么编译器就只能调用拷贝构造,const修饰的左值引用也可以引用右值。

C++11,STL的容器都是增加了移动构造和移动赋值的。

按照语法,右值引用只能引用右值,但右值引用一定不能引用左值吗?
有些场景下,可能真的需要用右值去引用左值实现移动语义。当需要用右值引用引用一个左值时,可以通过move函数将左值转化为右值。C++11中,std::move()函数位于 头文件中,该函数名字具有迷惑性,它并不搬移任何东西,唯一的功能就是将一个左值强制转化为右值引用,然后实现移动语义。

int main()
{
	string s1("hello world");
	// 这里s1是左值,调用的是拷贝构造
	string s2(s1);
	// 这里我们把s1 move处理以后, 会被当成右值,调用移动构造
	// 但是这里要注意,一般是不要这样用的,因为我们会发现s1的
	// 资源被转移给了s3,s1被置空了。
	string s3(std::move(s1));
 return 0;
}

C++11,STL容器插入接口函数也增加了右值引用版本

万能引用和完美转发

模板中的&&不代表右值引用,而是万能引用,其既能接收左值又能接收右值。模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力,如果不加处理,接收的类型,后续使用中都退化成了左值。

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)
{
	//不加处理不管穿的是什么,这里的t都是左值
	// 如果加了move(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;
}

我们希望能够在传递过程中保持它的左值或者右值的属性,那么就需要用到完美转发了。

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)
{
	//forward<T>就是完美转发
	Fun(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++的类有6个默认成员函数,C++11 新增了两个:移动构造函数和移动赋值运算符重载

如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造。
如果你没有自己实现移动赋值重载函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个,那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造完全类似)
如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。

类成员变量初始化
C++11允许在类定义时给成员变量初始缺省值,默认生成构造函数会使用这些缺省值初始化。

class A
{
publicA(){}
private:
	int _a = 0;
};

强制生成默认函数的关键字default
C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原因这个函数没有默认生成。比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以使用default关键字显示指定移动构造生成。

禁止生成默认函数的关键字delete
如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且只声明不定义,这样只要其他人想要调用就会报错。在C++11中更简单,只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。

那么今天的分享就到这里了,有什么不懂得可以私信博主,或者添加博主的微信,欢迎交流。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FC忍者神龟格斗可视化hack源码

[FC][忍者神龟格斗][最佳可视化][Final] 时间:2023.12.22 作者:FlameCyclone 内容: 1.可视化功能菜单 (1)菜单按键操作 1.上下键: 移动选项 2.左右键: 翻页 3.选择键: 翻转功能开关 4.开始键: 退出菜单 5.B键: 启用功能 …

如何进行实例管理

目录 修改实例规格 修改网络带宽 网站的访问量每天都比较高&#xff0c;网站明显变慢了&#xff0c;这是怎么回事&#xff1f; 这说明你的网站的并发访问能力已经不足了&#xff0c;并发访问是指同一时间&#xff0c;多个用户请求访问同一个域名下的资源或服务&#xff0c;请…

RHCE9学习指南 第10章 ACL权限

10.1 ACL介绍及基本用法 前面讲权限时是对u、u、o来设置权限的。假如有如图10-1所示的需求。 图10-1 为三个用户设置权限 有一个目录aa&#xff0c;要求tom、bob、mary具有不同的权限&#xff0c;利用前面讲过的知识是完全可以实现的。 所有者设置为tom&#xff0c;把所有者权…

目标追踪:使用ByteTrack进行目标检测和跟踪

BYTE算法是一种简单而有效的关联方法&#xff0c;通过关联几乎每个检测框而不仅仅是高分的检测框来跟踪对象。这篇博客的目标是介绍ByteTrack以及多目标跟踪&#xff08;MOT&#xff09;的技术。我们还将介绍在样本视频上使用ByteTrack跟踪运行YOLOv8目标检测。 多目标跟踪&…

【Python微信机器人】第六七篇: 封装32位和64位Python hook框架实战打印微信日志

目录修整 目前的系列目录(后面会根据实际情况变动): 在windows11上编译python将python注入到其他进程并运行注入Python并使用ctypes主动调用进程内的函数和读取内存结构体调用汇编引擎实战发送文本和图片消息(支持32位和64位微信)允许Python加载运行py脚本且支持热加载利用汇…

什么是数据可视化?数据可视化的流程与步骤

前言 数据可视化将大大小小的数据集转化为更容易被人脑理解和处理的视觉效果。可视化在我们的日常生活中非常普遍&#xff0c;但它们通常以众所周知的图表和图形的形式出现。正确的数据可视化以有意义和直观的方式为复杂的数据集提供关键的见解。 数据可视化定义 数据可视化…

「仙逆」王林夺舍身份曝光,火焚国火兽危机,两位始祖保护王林

Hello,小伙伴们&#xff0c;我是拾荒君。 《仙逆》第16集超前爆料&#xff0c;本次猛料&#xff0c;王林的天逆珠吞噬了火兽之王&#xff0c;使他的火属性达到了大圆满的境界。在封印屏障的保护下&#xff0c;他成功地逃脱了火兽的追击。然而&#xff0c;如今火兽数量众多&…

【视觉实践】使用Mediapipe进行手势识别

目录 1 Mediapipe 2 Solutions 3 安装依赖库 4 实践 1 Mediapipe Mediapipe是google的一个开源项目,可以提供开源的、跨平台的常用机器学习(machine learning,ML)方案。MediaPipe是一个用于构建机器学习管道的框架,用于处理视频、音频等时间序列数据。与资源消耗型的机…

易天新引进DELL Z9432F-ON交换机设备,网络通信再迎新风采

随着信息技术的飞速发展&#xff0c;网络通信已经成为现代社会中不可或缺的一部分。在这个数字化时代&#xff0c;企业对于高效、可靠的网络设备需求日益增加。为了满足企业日益增长的网络需求和为客户提供更好的服务&#xff0c;易天引进了DELL Z9432F-ON交换机设备&#xff0…

系统管理在工业物联网中的应用——青创智通工业物联网

工业物联网系统是一个复杂的大规模系统&#xff0c;涉及到众多的设备和系统&#xff0c;因此其管理面临诸多挑战。首先&#xff0c;设备和系统的多样性使得互通性成为一个难题&#xff0c;不同厂商的设备和系统之间的兼容性难以保证。其次&#xff0c;工业物联网系统的数据量庞…

Java开发框架和中间件面试题(5)

44.Tomcat一个请求的处理流程&#xff1f; 假设来自客户的请求为&#xff1a; http&#xff1a;//localhost&#xff1a;8080/test/index.jsp请求被发送到本机端口8080&#xff0c;被在那里侦听Copote HTTP/1.1 Connector,然后 1.Connector把该请求交给它所在的Service的Engi…

Antd Cascader 组件指定 placement 弹出位置无效

最近在使用 Antd Cascader 组件时&#xff0c;发现指定 placement 弹出位置无效&#xff0c;查看官方文档也没有找到相关的说明&#xff0c;经过一番搜索&#xff0c;终于发现了问题所在。 问题复现 代码示例&#xff1a; <Form.Item name"intention" label&quo…

7_js_dom编程入门1

Objective&#xff08;本课目标&#xff09; 掌握获取页面元素的常用方法 掌握事件触发案例 能够区分innerText和innerHTML的区别 综合案例训练 1 DOM 介绍 1.1 什么是DOM 文档对象模型&#xff08;Document Object Model&#xff0c;简称DOM&#xff09;&#xff0c;是 …

分享3种常用的前端埋点方式

只有了解用户&#xff0c;我们才能服务好用户&#xff0c;而最接近用户的我们&#xff0c;自然要承担起更多的责任。 那么在一个企业中&#xff0c;我们要如何去了解用户呢&#xff1f; 最直接有效的方式就是了解用户的行为&#xff0c;了解用户在网站中做了什么&#xff0c;呆…

工业交换机的冗余电源设计

在市场上&#xff0c;尤其是在工业级交换机上&#xff0c;我们经常能看到一个支持冗余电源的选项。在大多数工业现场中&#xff0c;我们都知道网络的稳定性是非常关键的。而且&#xff0c;像光伏和煤矿这样的行业经常位于偏远地区&#xff0c;环境条件恶劣。因此&#xff0c;在…

WAVE SUMMIT+ 2023倒计时2天,传文心一言将曝最新进展!

传文心一言将曝最新进展&#xff01; 亮点一&#xff1a;趋势引领&#xff0c;“扛把子”文心一言将曝新进展亮点二&#xff1a;干货十足&#xff0c;硬核低门槛开发秘籍大放送亮点三&#xff1a;蓄势待发&#xff0c;大模型赋能产业正当时亮点四&#xff1a;群星闪耀&#xff…

FPFA.一种二倍频电路代码描述以及测量详情

一、前言 1、因为需要倍频电路所以找了个二倍频的电路&#xff0c;通过fpga实际测量发现经过倍频后的电路峰值降低。不过这个也正常&#xff0c;因为该电路只要过触发点就会开始发生波形变化&#xff0c;而电路的触发值不是峰值。​​​​​​​ 2、继续对电路做倍频后信号做二…

西南科技大学计算机网络实验三 (路由器基本配置与操作,RIP、OSPF路由协议配置)

一、实验目的 基于网络设备模拟软件,学习和使用路由器的各种基本配置与验证命令,学习和使用路由器的静态路由、RIP、OSPF路由协议配置。 二、实验环境 使用RouterSim Network Visualizer软件来模拟网络设备与网络环境;主机操作系统为windows。 三、实验内容 1、路由器名称…

[足式机器人]Part4 南科大高等机器人控制课 CH11 Bascis of Optimization

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;CLEAR_LAB 笔者带更新-运动学 课程主讲教师&#xff1a; Prof. Wei Zhang 课程链接 &#xff1a; https://www.wzhanglab.site/teaching/mee-5114-advanced-control-for-robotics/ 南科大高等机器人控制课 Ch11 Bascis o…

android jetpack组件一篇搞定

Jetpack 是 Android 官方推出的一套开发库&#xff0c;其中包含众多的组件&#xff0c;可以让 Android 开发者更快更高效地开发应用程序。Jetpack 组件分为四大部分&#xff1a;架构、行为、UI 和基础组件。 下面详细阐述如何合理使用 Jetpack 组件开发 Android 项目。 1. 熟练…