【C++11(一)】右值引用以及列表初始化

news2025/1/11 11:44:54

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:C++从入门到精通⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习C++
  🔝🔝


在这里插入图片描述

C++11

  • 1. 前言
  • 2. 统一的列表初始化
  • 3. initializer_list容器讲解
  • 4. 左值与右值引用的初步认识
  • 5. 左值引用与右值引用比较
  • 6. 右值引用的使用场景以及价值
  • 7. 模板中的万能引用:&&
  • 8. 总结以及拓展

1. 前言

在C++98过后,更新的最重大,最有意义的就是C++11,
C++11新增了很多实用的内容,
C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,
不仅功能更强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多,
不仅如此,面试时也会问C++11的内容,所以我们要作为一个重点去学习

关于C++11的小故事:

在这里插入图片描述

本章重点:

本篇文章着重讲解C++11中新增的
统一的列表初始化{},及其底层容器:
initializer_list.并且会着重讲解C++11
中的右值引用相关内容,关于右值引用
的内容多并且杂,请同学们耐心学习!


2. 统一的列表初始化

请注意,用列表初始化和使用初始化
列表是两个完全不一样的概念!

不知道各位在写代码有没有这样写过:

vector<int> vv{1,2,3,4,5,6};
vector<int> vv = {1,2,3,4,5,6};

这就是使用列表来初始化容器!

C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。

即使都是用列表初始化,但种类可能不同:

class Date
{
public:
 Date(int year, int month, int day)
	 :_year(year)
	 ,_month(month)
	 ,_day(day)
 {}
private:
	 int _year;
	 int _month;
	 int _day;
 };
int main()
{
 Date d1(2022, 1, 1); // old style
 // C++11支持的列表初始化,这里会调用构造函数初始化
 Date d2{ 2022, 1, 2 };
 Date d3 = { 2022, 1, 3 };
 vector<int> v{1,2,3};
 return 0;
}

上面代码中,用列表初始化Date类和
vector类是不一样的,因为使用列表初
初始化Date时列表中的参数个数和类型
必须和Date中构造函数的参数个数类型
匹配,你不能写成Date d{2022}.但是在
vector初始化时,列表中的参数个数可以
是任意多个.

列表参数个数与构造函数一样的是隐式类型转换

你甚至可以这样用列表初始化:

vector<Date> vv{ {2023,12,2}, {2023,12,3}, {2023,12,4}};
map<string,int> mm{ {"西瓜",1}, {"苹果",2}, {"香蕉",3}};

3. initializer_list容器讲解

C++11中,大括号可以被识别为
一种类型,请看下面的代码验证:

auto it = { 1,2,3,4 };//li是initializer_list类型
cout << typeid(it).name() << endl;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

到这里,我们就能理解为啥STL的容器
可以支持用列表初始化了,因为它的内
部的构造函数和operator=函数重载了
参数是initializer_list的版本,所以当外界
使用列表初始化时,内部会识别为
initializer_list类型就会去调用特定的构造!

随便看看几个容器的构造版本:
(注意要看C++11版本的)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

并且initializer_list的内容不可修改
它指向的内容在常量区


4. 左值与右值引用的初步认识

首先,要先分清左值和右值的区别
左值的概念:

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名

// 以下的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;

右值的概念:

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

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;

注意,并不能用一个值能不能修改来区分左右值
const修饰的左值也不能修改,右值引用是&&

总结:

  • 区分左值和右值最常用的方法是看它
    能不能取地址,能取地址的是左值!

  • 虽然右值不能取地址,但是可以对使用
    右值引用后的变量取地址!

int&& r = 10;
int* pr = &r;

5. 左值引用与右值引用比较

先说它们两个的结论:

  • 左值引用只能引用左值,不能引用右值
    但const左值引用能引用右值

  • 右值引用只能引用右值,不能引用左值
    但右值引用可以引用move后的左值

代码检验:

// 左值引用只能引用左值,不能引用右值。
int a = 10;
int& ra1 = a;   // ra为a的别名
//int& ra2 = 10;   // 编译失败,因为10是右值
// const左值引用既可引用左值,也可引用右值。
const int& ra3 = 10;
const int& ra4 = a;
--------------------------------------------------
// 右值引用只能右值,不能引用左值。
int&& r1 = 10;
// error C2440: “初始化”: 无法从“int”转换为“int &&”
// message : 无法将左值绑定到右值引用
int a = 10;
int&& r2 = a;
// 右值引用可以引用move以后的左值
int&& r3 = std::move(a);

move是标准库中的一个函数,它可以将
一个变量/对象变成"将亡值",比如说现在
有一个数据的存在只是为了初始化另外
一个数据,那么如果不使用move的话,编译器
会将原先的数据给目标数据拷贝一份,并且
原先的数据即使已经没用了也会等到出了
作用域再销毁,加入我们使用move,编译器就
不会将原先的数据拷贝至目标数据,而是将
原先的数据直接给目标数据,而原先的数据清0!

在这里插入图片描述


6. 右值引用的使用场景以及价值

其实右值引用的价值刚刚已经谈到过了,
特别是在一些STL容器中,我们push一个
10,10是右值,此时不用拷贝直接此资源
做交换即可,或者说push了一个以后不需
要的值,也就是将亡值,此时也可以直接交换!

正因为如此,C++11的STL容器的构造
函数和赋值函数都重载了右值版本:

在这里插入图片描述
在这里插入图片描述

右值版本的构造很简单,直接swap资源即可
不需要像左值一样做拷贝,增加了效率!

//编译器识别为右值,直接调用右值引用版本的构造
string str("abcdef");
list<string> lt;
//move后编译器识别为右值,push后原本的str就被清0了
lt.push_back(move(str));

库中重载的右值引用版本的构造和赋值
被称为"移动构造"和移动赋值",它们极大的
提高的很多场景下的效率!

并且在函数返回值问题上,右值引用也能
发挥意想不到的作用,请看下面的例子:

string to_string(int val)
{
	string ret;
	//...将整数转换为字符串
	return ret;
}
string s1 = to_string(123);

如果没有移动构造和移动赋值,这里
return ret后会先将ret拷贝给临时对象
然后这个临时对象再把数据赋值给
外面的s1对象,这里要经历两次拷贝
可以说效率极其低下,其过程图如下:

在这里插入图片描述
假如我们实现的移动构造,编译器会把
ret识别为将亡值,就会去调用移动构造,
并且经过编译器的优化后,这两步拷贝
构造最终会被优化为一步移动赋值!

在这里插入图片描述


7. 模板中的万能引用:&&

模板中的&&不代表右值引用,而是万能引用,其既能接收左值又能接收右值,模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力

请看下面的代码:

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<class 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);//左值
	PerfectForward(std::move(b));//右值 
	return 0;
}

第一层per函数的参数既能接受左值
也能接受右值,但是假如你把代码复制
后测试,会发现在参数传递到第二层函数
时,它全部变成的左值,这是因为模板中的
万能引用会将右值退化成左值,所以后续
使用过程它就变成了左值!

使用forward可以保留对象的原生类型

void PerfectForward(T&& t)
{
	Fun(std::forward<T>(t));
}

注意,如果有多层调用,那么每一层都要加forward


8. 总结以及拓展

C++11之后,类的六个默认成员函数
又增加了两个,移动构造和移动赋值,
对于这两个函数需要注意下面几个点:

在这里插入图片描述

文章内容已经完结,有问题欢迎私信


🔎 下期预告:lambda表达式和包装器🔍

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

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

相关文章

C++ Easyx 让圆球跟随鼠标移动

目录 下载Easyx 检验 绘制窗口 画圆 响应事件的处理 清除原先绘图 渲染缓冲区 逻辑 代码托管 下载Easyx 在Easyx官网下载大暑版: 检验 写如下代码: 编译运行&#xff0c;如果控制台出现2023字样&#xff0c;代表配置成功: 绘制窗口 进入Eaxy官方网站&#xff0c;点…

【Java 基础】18 I/O流

文章目录 1.基本概念2.字节流3.字符流4.标准输入输出5.最佳实践 I/O流&#xff08;Input/Output 流&#xff09;是计算机程序中不可或缺的一部分&#xff0c; 往大了说所有的操作都是IO。Java 提供了强大而灵活的 I/O 框架&#xff0c;支持各种数据的 读取和 写入操作。 1.基…

Pandas操作数据库

一&#xff1a;Pandas读取数据库数据 二&#xff1a;Pandas读取海量数据 三&#xff1a;Pandas向数据库存数据 四&#xff1a;Pandas写入海量数据

docker 可视化工具操作说明 portainer

官网地址 https://docs.portainer.io/start/install-ce/server/docker/linux 1.First, create the volume that Port docker volume create portainer_data2.下载并安装容器 docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restartalways -v /var/run/docker…

web自动化 -- pyppeteer

由于Selenium流行已久&#xff0c;现在稍微有点反爬的网站都会对selenium和webdriver进行识别&#xff0c;网站只需要在前端js添加一下判断脚本&#xff0c;很容易就可以判断出是真人访问还是webdriver。虽然也可以通过中间代理的方式进行js注入屏蔽webdriver检测&#xff0c;但…

自然语言处理:电脑如何理解我们的语言?

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 ​ 文章目录 ​编辑 常见方法 1.基于词典的方法 2.基于计数的方法 基于推理的方法 Bert input_ids attention_mask token_type_ids 结语 在广…

英伟达狂卖50万台GPU!AI爆火背后,是显卡的争夺

据市场跟踪公司Omdia的统计分析&#xff0c;英伟达在第三季度大约卖出了50万台H100和A100 GPU&#xff01; 此前&#xff0c;Omdia通过英伟达第二季度的销售额&#xff0c;估计其大概卖出了900吨GPU&#xff01; 大语言模型火爆的背后&#xff0c;英伟达建立起了强大的显卡帝…

分治-归并排序

文章目录 &#x1f31e;315. 计算右侧小于当前元素的个数&#x1f308;1. 题目⛅2. 算法原理&#x1fa90;3. 代码实现 &#x1f315;493. 翻转对&#x1f320;1. 题目⭐2. 算法原理&#x1f31f;3. 代码实现 &#x1f31e;315. 计算右侧小于当前元素的个数 &#x1f308;1. 题…

深圳找工作的网站

深圳吉鹿力招聘网是一家在深圳做的比较好的招聘网站&#xff0c;提供一站式的专业人力资源服务&#xff0c;包括网络招聘、校园招聘、猎头服务、招聘外包、企业培训以及人才测评等。深圳吉鹿力招聘网在深圳的口碑相当好&#xff0c;是一个很好的选择。 深圳找工作用 吉鹿力招聘…

构建高效预约系统:深入探讨预约系统源码的设计和实现

随着各行业对高效资源利用和便捷服务的需求不断增加&#xff0c;预约系统成为了解决问题的有效工具。在这篇文章中&#xff0c;我们将深入研究预约系统源码的设计原则&#xff0c;并展示一些基本的技术代码&#xff0c;帮助读者更好地理解预约系统的实现方式。 设计原则 1. …

嘴尚绝卤味:健康卤味,未来餐饮市场的新星

随着人们生活水平的提高&#xff0c;对于吃的要求也越来越高。尤其是在快节奏的现代社会中&#xff0c;健康饮食成为了越来越多人的追求。在这种背景下&#xff0c;健康卤味这一新兴食品品类应运而生&#xff0c;成为了餐饮市场的新宠儿。 一、健康卤味的崛起 传统的卤味制作过…

「Verilog学习笔记」占空比50%的奇数分频

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 根据题意7分频&#xff0c;实际上是第一次电平变化经历了4个上升沿3个下降沿&#xff0c;第二次电平变化是4个下降沿3个上升沿&#xff0c;所以用两个计数器就行了。分别对…

Git:修改最近一次 Git 提交的描述,使用 --amend 选项

目录 步骤1. 使用编辑器修改最近一次提交的描述 git commit --amend2. 在编辑器中修改描述3. 保存修改4. 如果提交包含文件修改5. 强制推送&#xff08;如果已经推送到远程仓库&#xff09; 步骤 1. 使用编辑器修改最近一次提交的描述 git commit --amend git commit --amend…

软考初级、中级、高级怎么选?

本年度的PMP考试已经结束啦&#xff0c;对于刚考完的威宝和已经通过考试的威班们来说&#xff0c;刚开始接触PMP认证的时候在科普阶段有看到过“软考”的字眼。什么是软考&#xff0c;它主要考什么&#xff1f;通常用于哪些方面&#xff1f;软考又和PMP有什么关系&#xff1f;如…

备战春招——12.3 算法

哈希表 哈希表主要是使用 map、unordered_map、set、unorerdered_set、multi_&#xff0c;完成映射操作&#xff0c;主要是相应的函数。map和set是有序的&#xff0c;使用的是树的形式&#xff0c;unordered_map和unordered_set使用的是散列比表的&#xff0c;无序。 相应函数…

CityEngine2023 shp数据城市与路网三维模型并导入UE5

目录 0 引言1 城市和道路数据获取1.1 常用方法1.2 OSM数据获取1.3 OSM数据格式1.3.1 所有格式1.3.2 Shapefile格式 2 实践2.1 导入数据&#xff08;.shp&#xff09;2.2 构建三维模型2.3 将模型导入UE5 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xf…

mac M1芯片上编译车载aaos

一&#xff1a;mac上需要磁盘分区&#xff08;支持大小写&#xff09; mac分区&#xff1a; 在 Mac 上的“磁盘工具”中将物理磁盘分区 - 官方 Apple 支持 (中国) 注意&#xff1a;盘符名字不能有空格否则编译aaos时报错 注意&#xff1a;盘符名字不能有空格否则编译aaos时报…

2023.12.2 关于 Spring AOP 详解

目录 Spring AOP Spring AOP 常见使用场景 AOP 组成 切面&#xff08;类&#xff09; 切点&#xff08;方法&#xff09; 通知 ​编辑 前置通知&#xff08;Before&#xff09; 后置通知&#xff08;After&#xff09; 返回通知&#xff08;AfterReturning&#xff0…

认识DHT11温湿度传感器并制作温度报警器

Arduino UNO Arduino IDE开发环境 Arduino DHT11温湿度传感器 ​ 一、认识Arduino的DHT11温度湿度传感器 DHT传感器由电容式湿度传感器和热敏电阻两部分组成。除此之外&#xff0c;模块内部还有一些模拟信号到数字信号的转换&#xff0c;将温度湿度以数字信号的方式输…

EPS地形图绘制技巧--快捷键

如何导入外业点数据&#xff1f; &#xff08;1&#xff09;打开EPS软件&#xff0c;新建一个工程。如下&#xff1a; &#xff08;2&#xff09;在【文件】-【输入输出】-【调入坐标文件数据】中&#xff0c;调入测量点数据&#xff0c;如下&#xff1a; &#xff08;3&#…