C++11笑传之引用

C++11

  • 前言
  • 列表初始化
    • {}进行初始化
    • initializer_list
  • 右值引用和移动语义
    • 左值与右值
    • 左值引用与右值引用
    • 引用延长生命周期
    • 右值引用和移动语义的使用场景
    • 左值引用
    • 移动构造和移动赋值
  • 右值引用在容器插入的提效
  • 引用折叠
    • 万能折叠
    • 完美转发

前言

C++11是C++继98后的更新,其更新了许多内容,是非常重要的,除了我们前文所提到的范围for和auto,还有许多新的东西,对于C++11完全可以把它当成新的语言进行学习

列表初始化

{}进行初始化

C++11以后想统⼀初始化⽅式,试图实现⼀切对象皆可⽤{}初始化,{}初始化也叫做列表初始化。
内置类型⽀持,⾃定义类型也⽀持,⾃定义类型本质是类型转换,中间会产⽣临时对象,最后优化了以后变成直接构造。
{}初始化的过程中,可以省略掉=

int x2 { 2 };
Date d6 { 2024, 7, 25 };

C++11列表初始化的本意是想实现⼀个⼤统⼀的初始化⽅式,其次他在有些场景下带来的不少便利,如容器push/inset多参数构造的对象时,{}初始化会很方便

initializer_list

initializer_list是C++11之后提到的一个类,这个类的本质是底层开⼀个数组,将数据拷贝过来,initializer_list内部有两个指针分别指向数组的开始和结束。initializer_list与刚刚提到的{}初始化是不一样的,{}是基于构造函数,也就是说需要初始化每一个值都是需要对应的构造函数的。这样对于初始化容器就很不方便,例如初始化vector里的数,总不能写N个构造函数吧

vector<int> v1 ={1,2,3}

容器⽀持⼀个std::initializer_list的构造函数,也就⽀持任意多个值构成的 {x1,x2,x3…} 进⾏初始化。STL中的容器⽀持任意多个值构成的 {x1,x2,x3…} 进⾏初始化,就是通过initializer_list的构造函数⽀持的。

右值引用和移动语义

左值与右值

左值是⼀个表⽰数据的表达式(如变量名或解引用的指针),⼀般是有持久状态,存储在内存中,我们可以获取它的地址,左值可以出现赋值符号的左边,也可以出现在赋值符号右边。定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。
右值也是⼀个表⽰数据的表达式,要么是字面值常量、要么是表达式求值过程中创建的临时对象等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。
左值与右值的核心区别就是能否取地址

左值引用与右值引用

int& a = x;int&& b = y;

第一个语句就是左值引用,第二个就是右值引用。
左值引用不能直接引用右值,但是const左值引用可以引用右值
右值引用不能直接引用左值,但是右值引用可以引用move(左值)
move的作用就是强制转化为右值,但是属性还是左值的属性,只是类型强制转换。但是除非确定需要将左值转为右值,否则不要用move,因为move之后左值的资源会被窃取掉,那么左值又是会一直存在的,就会导致左值是一个悬空指针
需要注意的是变量表达式都是左值属性,也就意味着⼀个右值被右值引⽤绑定后,右值引⽤变量变量表达式的属性是左值,不然在后续进行移动语义的时候,如果右值引用后的属性是右值属性,那就无法修改了,也就无法移动了。

int* p = new int(0);
int b = 1;
const int c = b;
*p = 10;
string s("111111");
s[0] = 'x';
double x = 1.1, y = 2.2;
// 左值引⽤给左值取别名
int& r1 = b;
int*& r2 = p;
int& r3 = *p;
string& r4 = s;
char& r5 = s[0];
// 右值引⽤给右值取别名
int&& rr1 = 10;
double&& rr2 = x + y;
double&& rr3 = min(x, y);
string&& rr4 = string("11111");
// 左值引⽤不能直接引⽤右值,但是const左值引⽤可以引⽤右值
const int& rx1 = 10;
const double& rx2 = x + y;
const double& rx3 = min(x, y);
const string& rx4 = string("11111");
// 右值引⽤不能直接引⽤左值,但是右值引⽤可以引⽤move(左值)
int&& rrx1 = move(b);
int*&& rrx2 = move(p);
int&& rrx3 = move(*p);
string&& rrx4 = move(s);
string&& rrx5 = (string&&)s;

引用延长生命周期

右值引⽤可⽤于为临时对象延⻓⽣命周期,const 的左值引⽤也能延⻓临时对象⽣存期,但const对象⽆法被修改。

右值引用和移动语义的使用场景

左值引用

左值引⽤主要使⽤场景是在函数中左值引⽤传参和左值引⽤传返回值时减少拷⻉,同时还可以修改实参和修改返回对象的值。左值引⽤已经解决⼤多数场景的拷⻉效率问题,但是有些场景不能使⽤传左值引⽤返回,如addStrings和generate函数,C++98中的解决⽅案只能是被迫使⽤输出型参数解决。那么C++11以后这⾥可以使⽤右值引⽤做返回值解决吗?显然是不可能的,因为这⾥的本质是返回对象是⼀个局部对象,函数结束这个对象就析构销毁了,右值引⽤返回也⽆法改变对象已经析构销毁的事实。

移动构造和移动赋值

移动构造函数是⼀种构造函数,类似拷⻉构造函数,移动构造函数要求第⼀个参数是该类类型的引⽤,但是不同的是要求这个参数是右值引⽤,如果还有其他参数,额外的参数必须有缺省值。
移动赋值是⼀个赋值运算符的重载,他跟拷⻉赋值构成函数重载,类似拷⻉赋值函数,移动赋值函数要求第⼀个参数是该类类型的引⽤,但是不同的是要求这个参数是右值引⽤。
对于像string/vector这样的深拷贝的类或者包含深拷贝的成员变量的类,移动构造和移动赋值才有意义,因为移动构造和移动赋值的第⼀个参数都是右值引⽤的类型,他的本质是要“窃取”引⽤的右值对象的资源,⽽不是像拷⻉构造和拷⻉赋值那样去拷⻉资源,从提⾼效率。
在这里插入图片描述
必须得有移动构造函数才可以出现移动构造

string(string&& s)
{cout << "string(const string& s) -- 移动构造" << endl;this->swap(s);
}

移动构造是将右值与当前值进行交换,将有用的资源交换给需要的变量,这样相比与之前的拷贝构造出一个临时变量,再将临时变量拷贝构造给所需要的变量,效率要高很多

右值引用在容器插入的提效

• 查看STL文档我们发现C++11以后容器的push和insert系列的接⼝否增加的右值引⽤版本
在这里插入图片描述

• 当实参是⼀个左值时,容器内部继续调⽤拷贝构造进⾏拷贝,将对象拷贝到容器空间中的对象
• 当实参是⼀个右值,容器内部则调⽤移动构造,右值对象的资源到容器空间的对象上

引用折叠

• C++中不能直接定义引⽤的引⽤如 int& && r = i; ,这样写会直接报错,通过模板或 typedef中的类型操作可以构成引用的引用。
• 通过模板或 typedef 中的类型操作可以构成引用的引用时,这时C++11给出了⼀个引用折叠的规则:右值引用的右值引用折叠成右值引用,所有其他组合均折叠成左值引用。

typedef int& lref;
typedef int&& rref;
int n = 0;
lref& r1 = n; // r1 的类型是 int&
lref&& r2 = n; // r2 的类型是 int&
rref& r3 = n; // r3 的类型是 int&
rref&& r4 = 1; // r4 的类型是 int&&

万能折叠

template<class T>
void Function(T&& t)
{}

以上代码就是万能折叠,如果传的是int右值,T就会被识别成int,如果传的是int左值,T就会被识别成int&,这样就实现了传左值就是左值引用的参数,传右值就是右值引用的参数

完美转发

因为变量表达式的属性都是左值,即虽然传的是右值,在万能折叠下,t被识别成右值引用的类型,但由于t是变量表达式,所以如果把t传给其他函数,就会把其他函数的形参的属性变为左值,所以出现完美转发来解决这一问题。

template<class T>
void Function(T&& t)
{// 完美保持他的属性传参Fun(forward<T>(t));
}

完美转发forward是一个函数模版,可以把他与move相对应,move是将左值强制转化为右值,但是属性并不会发生改变,只是告诉编译器该左值是可以被窃取的,而forward是可以保持该对象的属性的,即t如果是右值引用,就会保持为右值引用,如果是左值,就会保持为左值

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

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

相关文章

瀚高数据库提交数据后,是否需要COMMIT(APP)

文章目录环境症状问题原因解决方案报错编码环境 系统平台&#xff1a; 版本&#xff1a;5.6.5,4.5 症状 瀚高数据库提交数据后&#xff0c;是否需要commit&#xff0c;瀚高数据库是否有配置项。 问题原因 瀚高数据库默认自动COMMIT&#xff08;提交数据&#xff09;&#…

深大计算机游戏开发实验三

主要步骤主角飞船的创建和移动边界设置以及护盾设置创建敌机自动生成敌机图层设置弹丸设置武器创建不同发射模式管理竞态条件击败敌机掉落升级道具不同敌机的生成分值显示实现退出游戏界面之后进入游戏的最高记录重置游戏界面失败后重新加载最记录不会重置任何时候在游戏界面按…

详解缓存淘汰策略:LRU

文章目录缓存淘汰策略LRU核心结构核心操作流程局限性源码走读AddGet缓存淘汰策略 缓存淘汰策略的存在是为了解决 缓存容量有限性 和 高缓存命中率 之间的矛盾。其核心目标是在有限的缓存空间内&#xff0c;尽可能提高缓存命中率 缓存容量有限性&#xff1a;缓存&#xff08;例…

什么是 Bootloader?怎么把它移植到 STM32 上?

一、Bootloader 是啥&#xff1f;它都干了些啥&#xff1f;想象一下你的 MCU&#xff08;比如 STM32&#xff09;是一个小机器人&#xff0c;上电之后第一件事&#xff0c;它不会立马开始“干正事”&#xff08;运行你的主程序&#xff09;&#xff0c;而是先去运行一个“开场引…

无人机避障——感知篇(Ego_Planner_v2中的滚动窗口实现动态实时感知建图grid_map ROS节点理解与参数调整影响)

处理器&#xff1a;Orin nx 双目视觉传感器&#xff1a;ZED2 实时感知建图方法&#xff1a;Vins Fusion Raycast &#xff08;VIO与射线投影法感知定位加建图方法&#xff09; 项目地址&#xff1a;https://github.com/ZJU-FAST-Lab/EGO-Planner-v2 【注意】&#xff1a;建…

26-计组-寻址方式

指令寻址与PC自增一、指令寻址方式定义&#xff1a;寻找下一条将要执行的指令地址的过程。 核心部件&#xff1a;程序计数器&#xff08;PC&#xff09;&#xff0c;用于指示待执行指令的地址。 执行流程&#xff1a;CPU根据PC值从主存取指令。取指后&#xff0c;PC自动自增&am…

生成式对抗网络(GAN)模型原理概述

生成对抗网络&#xff08;Generative Adversarial Network, GAN&#xff09;是一种通过对抗训练生成数据的深度学习模型&#xff0c;由生成器&#xff08;Generator&#xff09;和判别器&#xff08;Discriminator&#xff09;两部分组成&#xff0c;其核心思想源于博弈论中的零…

Vue和Element的使用

文章目录1.vue 脚手架创建步骤2.vue项目开发流程3.vue路由4.Element1.vue 脚手架创建步骤 创建一个文件夹 vue双击进入文件夹,在路径上输入cmd输入vue ui, 目的:调出图形化用户界面点击创建 9. 10.在vscode中打开 主要目录介绍 src目录介绍 vue项目启动 图形化界面中没有npm…

如何设置直播间的观看门槛,让直播间安全有效地运行?

文章目录前言一、直播间观看门槛有哪几种形式&#xff1f;二、设置直播间的观看门槛&#xff0c;对直播的好处是什么三、如何一站式实现上述功能&#xff1f;总结前言 打造一个安全、高效、互动良好的直播间并非易事。面对海量涌入的观众&#xff0c;如何有效识别并阻挡潜在的…

【SkyWalking】配置告警规则并通过 Webhook 推送钉钉通知

&#x1f9ed; 本文为 【SkyWalking 系列】第 3 篇 &#x1f449; 系列导航&#xff1a;点击跳转 【SkyWalking】配置告警规则并通过 Webhook 推送钉钉通知 简介 介绍 SkyWalking 告警机制、告警规则格式以及如何通过 webhook 方式将告警信息发送到钉钉。 引入 服务响应超时…

关于 验证码系统 详解

验证码系统的目的是&#xff1a;阻止自动化脚本访问网页资源&#xff0c;验证访问者是否为真实人类用户。它通过各种测试&#xff08;图像、行为、计算等&#xff09;判断请求是否来自机器人。一、验证码系统的整体架构验证码系统通常由 客户端 服务端 风控模型 数据采集 四…

微服务集成snail-job分布式定时任务系统实践

前言 从事开发工作的同学&#xff0c;应该对定时任务的概念并不陌生&#xff0c;就是我们的系统在运行过程中能够自动执行的一些任务、工作流程&#xff0c;无需人工干预。常见的使用场景包括&#xff1a;数据库的定时备份、文件系统的定时上传云端服务、每天早上的业务报表数…

依赖注入的逻辑基于Java语言

对于一个厨师&#xff0c;要做一道菜。传统的做法是&#xff1a;你需要什么食材&#xff0c;就自己去菜市场买什么。这意味着你必须知道去哪个菜市场、怎么挑选食材、怎么讨价还价等等。你不仅要会做菜&#xff0c;还要会买菜&#xff0c;职责变得复杂了。 而依赖注入就像是有一…

skywalking镜像应用springboot的例子

目录 1、skywalking-ui连接skywalking-oap服务失败问题 2、k8s环境 检查skywalking-oap服务状态 3、本地iidea启动服务连接skywalking oap服务 4、基于apache-skywalking-java-agent-9.4.0.tgz构建skywalking-agent镜像 4.1、Dockerfile内容如下 4.2、AbstractBuilder.M…

3. java 堆和 JVM 内存结构

1. JVM介绍和运行流程-CSDN博客 2. 什么是程序计数器-CSDN博客 3. java 堆和 JVM 内存结构-CSDN博客 4. 虚拟机栈-CSDN博客 5. JVM 的方法区-CSDN博客 6. JVM直接内存-CSDN博客 7. JVM类加载器与双亲委派模型-CSDN博客 8. JVM类装载的执行过程-CSDN博客 9. JVM垃圾回收…

UnityShader——SSAO

目录 1.是什么 2.原理 3.各部分解释 2.1.从屏幕空间到视图空间 2.2.以法线半球为基&#xff0c;获取随机向量 2.3.应用偏移&#xff0c;并将其转换为uv坐标 2.4.获取深度 2.5.比较并计算贡献 2.6.最后计算 4.改进 4.1.平滑过渡 4.2.模糊 5.变量和语句解释 5.1._D…

【设计模式】外观模式(门面模式)

外观模式&#xff08;Facade Pattern&#xff09;详解一、外观模式简介 外观模式&#xff08;Facade Pattern&#xff09; 是一种 结构型设计模式&#xff0c;它为一个复杂的子系统提供一个统一的高层接口&#xff0c;使得子系统更容易使用。 外观模式又称为门面模式&#xff0…

【6.1.1 漫画分库分表】

漫画分库分表 “数据量大了不可怕&#xff0c;可怕的是不知道如何优雅地拆分。” &#x1f3ad; 人物介绍 架构师老王&#xff1a;资深数据库架构专家&#xff0c;精通各种分库分表方案Java小明&#xff1a;对分库分表充满疑问的开发者ShardingSphere师傅&#xff1a;Apache S…

Tomcat问题:启动脚本startup.bat中文乱码问题解决

一、问题描述 我们第一次下载或者打开Tomcat时可能在控制台会出现中文乱码问题二、解决办法 我的是8.x版本的tomcat用notepad打开&#xff1a;logging.properties 找到&#xff1a;java.util.logging.ConsoleHandler.encoding设置成GBK&#xff0c;重启tomcat即可

Linux中Gitee的使用

一、Gitee简介&#xff1a;Gitee&#xff08;码云&#xff09;是中国的一个代码托管和协作开发平台&#xff0c;类似于GitHub或GitLab&#xff0c;主要面向开发者提供代码管理、项目协作及开源生态服务。适用场景个人开发者&#xff1a;托管私有代码或参与开源项目。中小企业&a…