C++11(左值(引用),右值(引用),移动语义,完美转发)

news2025/1/10 20:57:44

目录

一、左值与左值引用

1、左值

2、左值引用

3、意义

 二、右值与右值引用

1、右值

2、右值引用

三、右值引用使用场景和意义

1、右值的分类

2、移动构造

3、移动赋值

四、万能引用

五、完美转发 


一、左值与左值引用

1、左值

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,也可以出现在右边。

以下的p、b、c、*p都是左值: 

int* p = new int(0);
int b = 1;
const int c = 2;

注:定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。

2、左值引用

左值引用就是给左值的引用,给左值取别名。

以下几个是对上面左值的左值引用: 

int*& rp = p;
int& rb = b;
const int& rc = c;
int& pvalue = *p;

总结:

1、左值引用只能引用左值,不能引用右值。

// 左值引用只能引用左值,不能引用右值。
  int a = 10;
  int& ra1 = a;  // ra为a的别名
  //int& ra2 = 10;  // 编译失败,因为10是右值

2、但是const左值引用既可引用左值,也可引用右值。 

// const左值引用既可引用左值,也可引用右值。
  const int& ra3 = 10;
  const int& ra4 = a;

3、意义

1、做函数参数:减少拷贝,提高效率,可做输出型参数。

2、做函数返回值:减少拷贝,提高效率。引用返回,可修改返回对象 。


 二、右值与右值引用

1、右值

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

以下 10,x+y,fmin(x,y)都是常见的右值 :

double x = 1.1, y = 2.2;

10;
x + y;
fmin(x, y);

2、右值引用

右值引用就是对右值的引用,给右值取别名。 

以下几个都是对右值的右值引用: 

int&& rr1 = 10;
double&& rr2 = x + y;
double&& rr3 = fmin(x, y);

 注:右值是不能取地址的,但是给右值取别名后,会导致右值被存储到特定位置,且可以取到该位置的地址,也就是说例如:不能取字面量10的地址,但是rr1引用后,可以对rr1取地址,也可以修改rr1。如果不想rr1被修改,可以用const int&& rr1 去引用。

总结:

1、右值引用只能引用右值,不能引用左值。

// 右值引用只能右值,不能引用左值。
int&& r1 = 10;

//下面的错误
int a = 10;
int&& r2 = a;

2、但是右值引用可以引用move以后的左值。

// 右值引用可以引用move以后的左值
int&& r3 = std::move(a);

三、右值引用使用场景和意义

C++11为什么要增加右值引用呢?接着往下看。

我们看看 to_string的实现:

    string to_string(int value)
	{
		bool flag = true;
		if (value < 0)
		{
			flag = false;
			value = 0 - value;
		}
		hwc::string str;
		while (value > 0)
		{
			int x = value % 10;
			value /= 10;
			str += (x + '0');
		}
		if (flag == false)
		{
			str += '-';
		}
		std::reverse(str.begin(), str.end());
		return str;
	}

上面的代码中,str 是临时变量,出了作用域就会销毁,所以无法使用左值引用传返回值来减少拷贝、提高效率。 

如果函数的返回的是一个局部的对象,该对象出了函数作用域就被销毁了,这种情况下就不能用左值引用作为返回值了,只能以传值的方式返回(深拷贝)。这就是左值引用的不足之处。

基于上面的问题,右值引用就能够很好地解决这个问题。

1、右值的分类

内置类型右值 —— 纯右值。
自定义类型右值—— 将亡值。

2、移动构造

移动构造本质是将参数右值的资源窃取过来,占位已有,那么就不用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己
//拷贝构造
string(const string& s)
	:_str(nullptr)
	, _size(0)
	, _capacity(0)
{
	string tmp(s._str);
	swap(tmp);
}

//移动构造
string(string&& s)//右值引用
	:_str(nullptr)
    ,_size(0)
	,_capacity(0)
{
	swap(s);
}

to_string 没有调用深拷贝的拷贝构造,而是调用了移动构造,移动构造中没有新开空间,拷贝数据,所以效率提高了。

实现了string 的移动构造后,因为 to_string 的返回值是一个右值,是一个将亡值,所以如果 string 既有拷贝构造函数,也有移动构造函数,那么编译器会去调用移动构造,并且右值在出了作用域后会自动销毁。这里就是一个移动语义。

3、移动赋值

//拷贝赋值
string& operator=(const string& s)
{
	string tmp(s);
	swap(tmp);

	return *this;
}

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

四、万能引用

void Fun(int& x)
{
	cout << "17" << endl;
}

void Fun(int&& x)
{
	cout << "18" << endl;
}

template<typename T>
void fun(T&& t)
{
	Fun(t); //会被折叠
}

如上代码,在模板中的&&不代表右值引用,而是万能引用(引用折叠),其既能接收左值又能接收右值。模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力,但是引用类型的唯一作用就是限制了接收的类型,后续使用中都退化成了左值。

即:t 既能引用左值,也能引用右值。但是都会被折叠为左值引用。


五、完美转发 

从四中,我们知道了万能引用会被折叠为左值。但是如果我们本身就想传右值呢?我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用我们下面学习的完美转发。

std::forward 完美转发在传参的过程中保留对象原生类型属性。
如下代码:std::forward<T>(t)在传参的过程中保持了 t 的原生类型属性。
template<typename T>
void PerfectForward(T&& t)
{
    Fun(std::forward<T>(t));
}

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

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

相关文章

软件设计之抽象工厂模式

抽象工厂模式指把一个产品变成一个接口&#xff0c;它的子产品作为接口的实现&#xff0c;所以还需要一个总抽象工厂和它的分抽象工厂。 下面我们用一个案例去说明抽象工厂模式。 在class中可以选择super类和medium类&#xff0c;即选择一个产品的子类。在type中可以选择产品的…

LomBok的使用,MyBatis的使用(增删改查)

Lombok是一个Java库&#xff0c;能自动插入编辑器并构建工具&#xff0c;简化Java开发。通过添加注解的方式&#xff0c;不需要 为类编写getter或equels方法&#xff0c;同时可以自动化日志变量。 结构 pom <?xml version"1.0" encoding"UTF-8"?>…

LLM - FastAPI 搭建简易问答 Server

目录 一.引言 二.辅助函数 1.黑名单 2.清除函数 三.模型函数 1.加载模型 2.生成配置 四.服务部署 1.post - predict 2.get - clean_cache 3.main - run_app 五.总结 一.引言 SFT workflow 微调工作流程 一文中我们介绍了模型微调从数据到最终应用的流程 FastAPI …

C语言 选择(分支)

if 语句&#xff08;分支语句/选择语句&#xff09; 结构&#xff1a; if ( expressio ) statement 如果对 expression 求值为真&#xff08;非0&#xff09;&#xff0c;则执行 statement &#xff1b;否则&#xff0c;跳过 statement 。与 while 循环一样&#xff0c…

推荐两款不错的打字练习网站~

前言 对于写论文或者编程工作&#xff0c; 打字是其中十分耗费体力的一环&#xff0c;如果学会了盲打&#xff0c;那么可以起到事倍功半的作用。为了提高工作效率&#xff0c;我特意在网路上搜寻了大量打字练习的网站&#xff0c;最终发现有两款打字网站十分不错&#xff0c;同…

论文阅读-- A simple transmit diversity technique for wireless communications

一种简单的无线通信发射分集技术 论文信息&#xff1a; Alamouti S M. A simple transmit diversity technique for wireless communications[J]. IEEE Journal on selected areas in communications, 1998, 16(8): 1451-1458. 创新性&#xff1a; 提出了一种新的发射分集方…

搭建环境遇到的坑

office2010装完没法激活&#xff0c;因为没有关闭杀毒软件和防火墙。AWTK designer编译时报这个错&#xff0c;scons按这个方法装之后就好了。 装AWTK designer后&#xff0c;打不开软件&#xff0c;总是闪退&#xff0c;装了VS后就打得开了装IAR时找不到ActivationInfo.txt&am…

abp中iquery类使用orderBy接口功能报错问题

在后端写排序时&#xff0c;当使用如下OrderBy(排序字段)时&#xff0c;只引用System.Linq时如下错误&#xff1a; 只是因为缺少一个引用&#xff1a;System.Linq.Dynamic.Core  在如下类文件中引用 System.Linq.Dynamic.Core  注意&#xff1a;切记不能删掉System.Linq的引…

STM32 CubeMX ADC采集(HAL库)

STM32 CubeMX ADC采集&#xff08;HAL库&#xff09; STM32 CubeMX STM32 CubeMX ADC采集&#xff08;HAL库&#xff09;ADC介绍ADC主要特征一、STM32 CubeMX设置二、代码部分三&#xff0c;单通道轮询采样速度总结 ADC介绍 12位ADC是一种逐次逼近型模拟数字转换器。它有多达1…

springboot整合rabbitmq入门(三)

在上一篇文章中介绍了rabbitmq的fanout模式。今天继续学习另一种模式——direct模式。这种模式是rabbitmq的最简单一种模式。 首先创建一个名为helloDirect1的对列 Configuration public class DirectRabbitConfig {Beanpublic Queue directA(){return new Queue("hell…

【翻译】NCLS: Neural Cross-Lingual Summarization

Abstract 跨语言摘要&#xff08;CLS&#xff09;是为不同语言的源文件生成特定语言摘要的任务。现有方法通常将此任务分为两个步骤&#xff1a;摘要和翻译&#xff0c;导致错误传播的问题。为了解决这个问题&#xff0c;我们首次提出了一种端到端的CLS框架&#xff0c;我们称…

淘宝商品销量数据接口,淘宝商品销量数据API接口

淘宝商品销量数据接口是淘宝开放平台提供的一种API接口&#xff0c;通过该接口&#xff0c;商家可以获取到淘宝平台上某一商品的销量数据&#xff0c;包括商品的总销量、近期销量、销售趋势等。 该接口的使用方法是&#xff0c;商家先注册淘宝开放平台账号&#xff0c;申请App…

体会jdk17对于空指针的增强

jdk17 // 可以清楚的看出来a.b.c.num中由于c是空指针&#xff0c;所以导致异常 jdk11 // 只报第6行空指针了&#xff0c;但是因为哪个变量&#xff0c;不知道

打exit_hook,如何找exit_hook的偏移

最近在打比赛的时候&#xff0c;一眼就知道咋做了&#xff0c;打exit_hook为one_gadget 但是泄露出libc之后&#xff0c;没法找到exit_hook的偏移&#xff0c;所以没能拿到一血。搜了好多&#xff0c; 总结大概就是exit_hook不是真实存在的&#xff0c;而是函数指针&#xff0c…

ansible - Role

1、简介&#xff1a; Ansible 中的角色&#xff08;Role&#xff09;是一种组织和封装Playbook的方法&#xff0c;用于管理和组织 Ansible代码。它可以将任务和配置逻辑模块化&#xff0c;以便在不同的Playbook中共享和重用。 2、通过 role 远程部署并配置 nginx (1) 准备目…

【FISCO-BCOS】十七、角色的权限控制

目录 一、角色定义 二、账户权限控制 1.委员新增、撤销与查询 2.委员权重修改 3.委员投票生效阈值修改 4. 运维新增、撤销与查询 一、角色定义 分为治理方、运维方、监管方和业务方。考虑到权责分离&#xff0c;治理方、运维方和开发方权责分离&#xff0c;角色互斥。 治理…

pytorch_神经网络构建2(数学原理)

文章目录 深层神经网络多分类深层网络反向传播算法优化算法动量算法Adam 算法 深层神经网络 分类基础理论: 交叉熵是信息论中用来衡量两个分布相似性的一种量化方式 之前讲述二分类的loss函数时我们使用公式-(y*log(y_)(1-y)*log(1-y_)进行概率计算 y表示真实值,y_表示预测值 …

MyBatisPlus(十五)分页查询

说明 MyBatisPlus 提供了分页查询的功能。 MyBatisPlus 的分页功能&#xff0c;是通过分页插件实现的。要使用分页功能&#xff0c;需要配置分页插件的拦截器。 MyBatisPlus 的分页功能&#xff0c;可以通过内置的API接口实现&#xff1b;也可以通过自定义的 mapper#method …

第七章 正交实验法用例评审bug管理流程

一、正交试验法 利用因果图来设计测试用例时,作为输入条件的原因与输出结果之间的因果关系,有时很难从软件需求规格说明中得到。往往因果关系非常庞大,以至于据此因果图得到的测试用例数目多的惊人,给软件测试带来沉重的负担,为了有效地合理地减少测试的工时与费用,可利…

合并不同门店数据-上下合并

项目背景&#xff1a;线下超市分店&#xff0c;统计产品的销售数量和销售额&#xff0c;并用透视表计算求和 merge()函数可以根据链接键横向连接两张不同表&#xff0c;concat()函数可以上下合并和左右合并2种不同的合并方式。merge()函数只能横向连接两张表&#xff0c;而con…