【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跨域问题解决方案(…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...

tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...