【C++11(一)】右值引用以及列表初始化
💓博主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之后,类的六个默认成员函数
又增加了两个,移动构造和移动赋值,
对于这两个函数需要注意下面几个点:
文章内容已经完结,有问题欢迎私信
相关文章:

【C++11(一)】右值引用以及列表初始化
💓博主CSDN主页:杭电码农-NEO💓 ⏩专栏分类:C从入门到精通⏪ 🚚代码仓库:NEO的学习日记🚚 🌹关注我🫵带你学习C 🔝🔝 C11 1. 前言2. 统一的列表初始化3. initializer…...
通俗理解Jenkins是什么?
目录 通俗理解 Jenkins是什么? 通俗理解 假设你有一个软件项目,多个开发者在一起写代码。每当有人提交新的代码时,你想要自动地构建、测试这些代码,确保它们没有引入问题。 Jenkins就像一个聪明的助手,会在有人提交…...

格雷希尔帮助仪器仪表测试时快速密封的G60C系列接头其优势有哪些
仪器仪表在工业领域中扮演着重要的角色,如:压力表,压力传感器、压力变送器、压力开关、压力歧管等这些,在工业领域中都是随处可见的,其数据的精度直接影响着产品在生产过程中的质量和安全性;因此࿰…...

系统运维工具KSysAK——让运维回归简单
系统运维工具KSysAK——让运维回归简单 1.基本信息 1.1概述 系统异常定位分析工具KSysAK是云峦操作系统研发及运维人员总结开发及运维经验,设计和研发的多个运维工具的集合,可以覆盖系统的日常监控、线上问题诊断和系统故障修复等常见运维场景。 工具…...

NowCoder | KY11 二叉树遍历
NowCoder | KY11 二叉树遍历 OJ链接 简单来说就是构建这个二叉树定义结构体通过递归方式根据输入的字符串构建二叉树。对于输入字符串中的每个字符,如果是 ‘#’ 表示空节点,否则创建一个新节点,并递归地构建左右子树。 #include <limit…...

android.view.WindowLeaked解决方法
问题 我在使用WindowManager添加一个button, windowManager.addView(button,layoutParams);然后关闭当前的这个Activity的时候遇到了WindowLeak这个问题,也就是所谓的窗体泄露。 原因 主要原因是因为android只允许在UI主线程操作,我在使用W…...

浪潮信息KeyarchOS的飞跃之路
1.背景 在正式向大家介绍KOS之前,我们先关注这样一些问题。 传统操作系统在大规模数据处理、高性能计算和人工智能应用方面面临着一些瓶颈问题,包括存储和访问效率、数据传输和通信效率、并行计算性能等等问题。为了能够更好的改进这些问题,…...

C++基础 -41- 迭代器
每个stl 模板接口都有一个专用的迭代器 迭代器就是 stl 库中的 一个特殊指针,功能与指针类似(类似但不是) 迭代器定义格式 迭代器的使用,使用迭代器遍历向量容器的参数 代码运行结果 无论使用普通方式还是迭代器方式去都可以遍历vector容器...

zookeeper心跳检测 (实操课程)
本系列是zookeeper相关的实操课程,课程测试环环相扣,请按照顺序阅读来学习和测试zookeeper。 阅读本文之前,请先阅读----zookeeper 单机伪集群搭建简单记录(实操课程系列)zookeeper 客户端常用命令简单记录…...

社区新零售:重塑零售业的全新模式
社区新零售:重塑零售业的全新模式 近年来,新零售业成为了研究的焦点,它是一种以互联网为基础的零售形式。新零售通过运用先进技术手段,如大数据和人工智能,对商品的生产、流通和销售过程进行升级改造,重新构…...

北京华联BHGMall“宠粉模式”不断迭代,强体验注互动成行业UP主
在今年双11热度遇冷后,双十二被官宣取消,而这背后本质已经间接印证:传统“电商大促”的模式,已经难以为继。反观线下消费市场,则是以持续恢复和增长成为经济恢复的亮点,从线下客流量的快速回升,…...

前端时间的失败总结复盘
分享失败经验,前段时间的总结复盘: 与伙伴合作面对异常决策要及时提出质疑,怼,别太客气,客气起来,小心翼翼在意他人情绪那么这个项目就会让人难受,不要因为因为伙伴身上有标签/光环/权威就觉得…...

Ribbon 负载均衡
1、负载均衡整体流程 2、负载均衡流程逐级跟踪运行 (1) LoadBlanced 注解可以使LoadBalancerInterceptor拦截到; (2)LoadBalancerInterceptor 实现了ClientHttpRequestInterceptor接口; (3)ClientHttpRequestInterceptor接口释义如下; (4)int…...

微服务实战系列之Cache(技巧篇)
前言 凡工具必带使用说明书,如不合理的使用,可能得到“意外收获”。这就好比每个人擅长的领域有所差异,如果放错了位置或用错了人,也一定会让 Leader 们陷入两难之地:“上无法肩负领导之重托,下难免失去伙伴…...

6.17验证二叉树(LC98-M)
算法: 中序遍历下,输出的二叉搜索树节点的数值是有序序列。 有了这个特性,验证二叉搜索树,就相当于变成了判断一个序列是不是递增的了。 具体地:中序遍历时,判断当前节点是否大于中序遍历的前一个节点&a…...

【Linux】编译器-gcc/g++与调试器-gdb的使用
👀樊梓慕:个人主页 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》 🌝每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.gcc/g语法 2.gcc的使用及…...
Google Guava 散列工具使用详解
文章目录 散列哈希函数哈希码布隆过滤器 散列 Guava 提供了一组散列(哈希)相关的工具类和方法,包括哈希函数接口、哈希算法实现、哈希码(HashCode)类、布隆过滤器(BloomFilter)等等。 Guava 提…...
AIGC-文生视频
stable diffusion的前传: 轻松理解 VQ-VAE:首个提出 codebook 机制的生成模型 - 知乎近两年,有许多图像生成类任务的前沿工作都使用了一种叫做"codebook"的机制。追溯起来,codebook机制最早是在VQ-VAE论文中提出的。相比…...
java中Collectors.groupingBy返回实例?
在Java中,Collectors.groupingBy()是一个用于对流元素进行分组的收集器。它可以根据指定的分类函数对流元素进行分组,并返回一个Map对象,其中键是分组的标准,值是属于相应组的元素列表。 下面是一个使用Collectors.groupingBy()方…...
uniapp打包的h5项目多了接口调用https://api.next.bspapp.com/client
产生跨域问题。 这个实际上是因为该项目在manifest.json文件中勾选了‘uni统计配置’导致的,取消勾选就可以了。 如果是小程序项目,在小程序开发者工具中添加可信任域名就可以了。 可以看看下面这个链接内容 uni-app H5跨域问题解决方案(…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...

莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...