C++11右值引用及移动构造

news2024/11/16 1:36:40

区分左值和右值

在学习c++11的右值引用前,大家肯定会有点陌生什么是右值?什么是左值?现在我先来带大家熟悉一下概念。

左值

可以被取地址,也可被修改(const修饰的除外)

可以出现在等号左边,也可以出现在右边

	//a,b,c均为左值
	int a = 1;//a出现在等号左边
	const int b = a;//a出现在等号右边
	int* c = new int;

 右值

举例:字母常量、表达式的返回值、函数的返回值(不能是左值引用返回)等等。

不可以被取地址,不可被修改

只能出现在等号右边,不能出现在等号左边(因为不可被修改)

	int x = 2, y = 1;
	//下面常见的右值
	10;
	"xxxxxx";
	x + y;
	fmax(x, y);

如何区分?

误区:许多小伙伴喜欢看这个值在等号的哪边来区分这个值是左值还是右值,其实是不正确的,正确的区分方法应该是判断这值是否能被取地址! 

左值引用:

左值引用也就是对左值取别名,其实我们之前学习的引用就是左值引用,用符号&来声明,比如:

	//a,b,c均为左值
	int a = 1;//a出现在等号左边
	int b = a;//a出现在等号右边
	int* c = new int;
	//d,e,f均为左值引用
	int& d = a;
	int& e = b;
	int& f = *c;

这里其实和大家之前学的引用一样,就不过多赘述。

右值引用

 右值引用也就是对右值取别名,用符号&&来声明,比如:

	int x = 2, y = 1;
	//下面是常见的右值
	10;
	"xxxxxx";
	x + y;
	fmax(x, y);
	//下面是常见的右值引用
	int&& a = 10;
	string&& b = "xxxxx";
	int&& c = x + y;
	int&& d = fmax(x, y);

特别注意:

右值引用本身是左值! 右值引用本身是左值! 右值引用本身是左值! 

也就是说上面代码中的 a,b,c,d均是左值!!!

原因很简单,如果右值引用本身还是右值,那么右值引用将毫无意义,无法修改,进行后续操作。

左值引用及右值引用的意义

正所谓知其然,知其所以然。

想要彻底掌握这两种引用的用法,我们就需先了解这两种引用的出现意义和历史渊源。

现在我带大家从c语言讲起:

C语言的弊端:

大家在学习c++初期时,想必都了解过,c++其实是为了解决c语言的大部分弊端,而衍生出来的新语言,那么引用的出现,究竟是为了解决哪些弊端呢?请看如下代码:

#include<iostream>
using namespace std;
void my_swap(int x,int y)
{
	int t = x;
	x = y;
	y = t;
}
int main()
{
	int x = 1;
	int y = 2;
	cout << "x=" << x << " " << "y=" << y << endl;
	my_swap(x, y);
	cout << "x=" << x << " " << "y=" << y << endl;
	return 0;
}

运行结果:

我实现了一个简单的交换函数,为什么最后的值没有交换?

原因很简单,函数里的x,y是形参,形参只是实参的一份临时拷贝,形参的修改不会影响到实参,那么c语言是如何解决这个问题的呢?

没错,使用指针!

#include<iostream>
using namespace std;
void my_swap(int* x,int* y)
{
	int t = *x;
	*x = *y;
	*y = t;
}
int main()
{
	int x = 1;
	int y = 2;
	cout << "x=" << x << " " << "y=" << y << endl;
	my_swap(&x, &y);
	cout << "x=" << x << " " << "y=" << y << endl;
	return 0;
}

左值引用的诞生

但是在c++看来指针繁琐且难以理解,故c++创造了左值引用来解决这类问题:

#include<iostream>
using namespace std;
void my_swap(int& x,int& y)
{
	int t = x;
	x = y;
	y = t;
}
int main()
{
	int x = 1;
	int y = 2;
	cout << "x=" << x << " " << "y=" << y << endl;
	my_swap(x, y);
	cout << "x=" << x << " " << "y=" << y << endl;
	return 0;
}

左值引用还可作返回值:

using namespace std;
class my_string
{
public:
	my_string(string str = "xxxxx")
	{
		_str = str;
	}
	my_string& operator+=(char s)
	{
		_str.push_back(s);
		return *this;
	}
private:
	string _str;
};
int main()
{
	my_string s1("test ");
	my_string s2 = s1 += 'a';
	return 0;
}

如果不用左值引用返回,直接传值返回,那么返回时还要进行一次拷贝,这样大大降低了效率,左值引用的出现,减少了拷贝,大大提高了效率。

注意:

左值引用作返回值时,返回的自定义类型必须出了作用域(函数体)仍然存在,才可使用,不然就会出现野引用。

所以如果我们在函数体里面创建了一个自定义类型,是不能左值引用返回的,因为这个自定义类型是在函数里面创建的,出了函数体就不存在了。比如(错误示范):

	my_string& operator+(char s)
	{
		string str1(_str);
		str1.push_back(s);
		my_string str2(str1);
		return str2;
	}

上面str2出了函数体就释放了,所以不能用左值引用返回。 

到这里不难总结出,左值引用虽然在某些情况,减少了拷贝,大大提高了代码的效率,但是不全面,还是有些场景下会出现不可避免的拷贝问题。

右值引用的诞生

c++11更新后为了弥补左值引用的不足,创造出了右值引用,完全彻底避免了不必要的拷贝,没错就是右值引用返回。

继续看到上面的代码,引入一个新名词:将亡值 也就是str2,顾名思义,将亡值也就是即将消亡的值,正如str2出了函数体后直接释放,那么右值引用又是如何解决这个问题的呢?

#include<iostream>
#include<string>
using namespace std;
class my_string
{
public:
	my_string(string str = "xxxxx")
	{
		_str = str;
	}
	void swap(my_string& str)
	{
		std::swap(_str, str._str);
	}
	my_string(my_string&& s)//移动构造
	{
		swap(s);
	}
	my_string&& operator+(char s)
	{
		string str1(_str);
		str1.push_back(s);
		my_string str2(str1);
		return move(str2);
	}
private:
	string _str;
};

右值引用返回+移动构造,通过上述代码不难看出,移动构造其实就是将即将释放的将亡值str2的资源直接通过swap函数转移出来,大大减少了拷贝。

移动赋值同理。

移动构造及移动赋值特点

移动构造和移动赋值也是类的默认成员函数,一般其它的默认成员函数,都是自己不写,编译器自动生成,但这两个默认构造函数略有不同:

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

 关于红字部分原因很简单,一般涉及到深拷贝时,就都要实习那析构,拷贝构造,拷贝赋值,移动构造,移动赋值,所以这些函数差不多是绑定在一块的。

完美转发

模板中的&&万能引用:

注意&&如果出现在模板中,那么它代表的不一定是右值引用,而是万能引用,既可以接受左值,又可以接收右值。

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; }
// std::forward<T>(t)在传参的过程中保持了t的原生类型属性。
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;
}

运行结果:

注意,如果不加forward,那么如果传的是右值那么t本身会变成左值,因为右值引用本身是左值。

不加forward运行结果: 

 

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

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

相关文章

华为HCIP Datacom H12-821 卷29

1.多选题 下面关于LSA age字段&#xff0c;描述正确的是∶ A、LSA age的单位为秒&#xff0c;在LSDB中的LSA的LS age随时间增长而增长 B、LSA age的单位为秒&#xff0c;在LSDB中的LSA的LS age随时间增长而减少 C、如果一条LSA的LS age达到了LS RefreshTime&#xff08…

【C++】AVL树(旋转、平衡因子)

&#x1f308;个人主页&#xff1a;秦jh_-CSDN博客&#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/qinjh_/category_12575764.html?spm1001.2014.3001.5482 ​ 目录 前言 AVL树的概念 节点 插入 AVL树的旋转 新节点插入较高左子树的左侧---左左&#xff1a;…

Spring的AOP基础以及AOP的核心概念

2. AOP基础 学习完spring的事务管理之后&#xff0c;接下来我们进入到AOP的学习。 AOP也是spring框架的第二大核心&#xff0c;我们先来学习AOP的基础。 在AOP基础这个阶段&#xff0c;我们首先介绍一下什么是AOP&#xff0c;再通过一个快速入门程序&#xff0c;让大家快速体…

高级RAG检索中的五种查询重写策略_用于检索增强的大型语言模型的查询重写

一、前言 检索增强生成 (RAG) 作为人工智能 (AI) 领域的一项重要技术&#xff0c;近年来得到了飞速发展。它将基于检索模型和基于生成的模型相结合&#xff0c;利用海量外部数据&#xff0c;生成更具信息量、更准确、更具语境相关性的回复。检索策略是 RAG 系统的关键组成部分…

2024年最适合高级网工的11款Linux

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 你们好&#xff0c;我的网工朋友。 Linux作为一个免费且开源的操作系统&#xff0c;随着时间的推移催生了多个发行版&#xff0c;并且得到了庞大…

golang验证Etherscan上的智能合约

文章目录 golang验证Etherscan上的智能合约为什么要验证智能合约如何使用golang去验证合约获取EtherscanAPI密钥Verify Source Code接口Check Source Code Verification Status接口演示示例及注意事项网络问题无法调用Etherscan接口&#xff08;最重要的步骤&#xff09; golan…

应用层协议原理——因特网提供的运输服务

我们已经考虑了计算机网络能够一般性地提供的运输服务。现在我们要更为具体地考察由因特网提供的运输服务类型。因特网(更一般的是TCP/IP网络)为应用程序提供两个运输层协议&#xff0c;即UDP和TCP。当软件开发者为因特网创建一个新的应用时&#xff0c;首先要做出的决定是&…

js逆向案例 | 加速乐反爬逆向

前言 加速乐作为一种常见的反爬虫技术&#xff0c;在网络上已有大量详尽深入的教程可供参考。然而&#xff0c;对于那些初次接触的人来说&#xff0c;直接面对它可能仍会感到困惑。 声明 本文仅用于学习交流&#xff0c;学习探讨逆向知识&#xff0c;欢迎私信共享学习心得。如…

收银系统源码-商品报损管理

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物等连锁店使用。 详细介绍请…

ESXi6.7 update 3主机实现新硬件运行老环境

server 2003 SQL server 2000 SQL SP4 vmware tools 一、适用场景 1、运行多年的老企业&#xff0c;积累的数据量庞大&#xff0c;其中的数据库并不一定都是现在开发的平台或系统&#xff0c;而是已经正在运行&#xff0c;不能停业务的状态。 2、老系统老应用平台&#xf…

day01:项目概述,环境搭建

文章目录 软件开发整体介绍软件开发流程角色分工软件环境 外卖平台项目介绍项目介绍定位功能架构 产品原型技术选型 开发环境搭建整体结构&#xff1a;前后端分离开发前后端混合开发缺点前后端分离开发 前端环境搭建Nginx 后端环境搭建熟悉项目结构使用Git进行版本控制数据库环…

Day06-01-lvs

Day06-01-lvs 0. 核心内容1.负载均衡项目 选择故障: 2.lvs 预备姿势-arp3.lvs 概述4. lvs工作模式4.1 预备姿势4.2 lvs-dr模式4.3 lvs-nat模式4.4 小结 5. lvs-dr模式5.1 环境准备5.2 lvs-dr模式配置流程1) lvs服务端配置2) web服务器 RS服务端配置3) 小结4) 调试 5.3 抓包查看…

电脑清理软件用哪个好?这款工具有些饱受争议

电脑清理软件用哪个好?电脑作为我们工作和娱乐的重要工具&#xff0c;其运行速度和安全性直接影响着我们的生活质量。然而&#xff0c;随着时间的推移&#xff0c;电脑系统会积累大量垃圾文件、注册表错误、恶意软件等&#xff0c;导致电脑运行缓慢甚至崩溃。 这时&#xff0c…

el-tree 获取当前勾选节点的选中状态以及选中值对象 触发check-change多次事件问题原因

1.需求 现在需要一个树状结构的资产树 但是现在需求是 获取当前选中的值的状态是选中还是取消选中 然后再用当前选中 or 取消选中的值 进行 选中 or 取消选中的操作 一开始使用的是 check-change 方法 接收参数如图 但是我勾选父节点 或者 子节点后 他会打印一堆数据 是因…

基于Java+SpringMvc+Vue技术的智慧校园系统设计与实现

博主介绍&#xff1a;硕士研究生&#xff0c;专注于信息化技术领域开发与管理&#xff0c;会使用java、标准c/c等开发语言&#xff0c;以及毕业项目实战✌ 从事基于java BS架构、CS架构、c/c 编程工作近16年&#xff0c;拥有近12年的管理工作经验&#xff0c;拥有较丰富的技术架…

昇思25天学习打卡营第11天 | LLM原理和实践:基于MindSpore实现BERT对话情绪识别

1. 基于MindSpore实现BERT对话情绪识别 1.1 环境配置 # 实验环境已经预装了mindspore2.2.14&#xff0c;如需更换mindspore版本&#xff0c;可更改下面mindspore的版本号 !pip uninstall mindspore -y !pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore2.2…

geospy.AI 根据图片定位地理位置

文章目录 简介场景标志性建筑平凡的商店名标志性的物品标志性的地理位置标志性的街道难以分辨的古建筑不出名的山水 简介 GeoSpy.ai 作为一个地理空间情报平台&#xff0c;可以在以下场景中使用&#xff1a; 农业&#xff1a;监控农作物生长情况&#xff0c;预测产量&#xf…

课设:二手车交易管理系统(Java+MySQL)

简易数据库课程设计~分享 技术栈 本项目使用以下技术栈构建&#xff1a; Java: 作为主要编程语言&#xff0c;负责业务逻辑的实现。MySQL: 用于数据存储&#xff0c;管理用户、车辆和订单信息。JDBC: 用于Java与MySQL数据库之间的连接和操作。Swing GUI: 提供用户图形界面&am…

数据库课设---酒店管理系统(MySQL、VBNet)

目录 一. 知识技术 二. 需求分析 2.1 功能需求 2.2 数据需求 三. 数据流图与数据字典 3.1 数据流图 3.1.1 业务流图 3.1.2 数据流图 3.1.3 关系图 3.2 数据字典 四. 数据库设计 4.1 概念模型设计 4.2 逻辑模型设计 4.3 数据库实现 …

【LSB图像低位隐写】字符串隐写

按照自己的理解写了一个简单的字符串隐藏在图像中的python代码 前言 脱胎于内容安全的大作业~ 目前第一阶段&#xff0c;只完成了字符串隐藏在图像中 步过图像隐藏在图像应该异曲同工&#xff0c;之后实现~ 一、代码 图像的output路径和input路径写死了&#xff0c;这个需要…