C++:C++11新特性---右值引用
文章目录
- 初始化方式
- 显示查看类型
- initializer_list
- decltype
- 左值引用和右值引用
- move
- 左右值引用的场景
- 万能引用和完美转发
本篇总结C++11新特性
初始化方式
C++11对参数列表的初始化有了更明确的定义,可以这样进行定义
// 列表初始化
void test1()
{// 旧版本int x = 0;// 新版本int y{ 0 };int z = { 0 };int arr[]{ 10,20,30 };int* pa = new int[5]{ 1,2,3,4,5 };
}
在对类的赋值的时候,也可以这样进行赋值
struct t
{int a;int b;
};void test2()
{t* pt = new t[5]{ 1,2 };
}
显示查看类型
// 查看类型
void test3()
{int a = 1;cout << typeid(a).name() << endl;auto it = map<int, int>().begin();cout << typeid(it).name() << endl;
}
运行结果:
int
class std::_Tree_iterator<class std::_Tree_val<struct std::_Tree_simple_types<struct std::pair<int const ,int> > > >
initializer_list
这是什么呢?如何理解这个类型?先看一下在什么场景中会出现这个东西
void test4()
{auto lit = { 1,2,3,4 };cout << typeid(lit).name() << endl;
}
那么这个东西是干什么的呢?有什么用呢?
在C++11中,对于STL的各类容器的构造函数中,新增了这样的构造方式,有点类似于一个数组,它里面可以存储任意类型的数据,然后可以交给vector来实现构造,因此下面就要对{}进行一个对比
void test5()
{// 利用initializer_list进行初始化vector<int> v{ 1,2,3,4,5 };auto lit = { 1,2,3,4 };vector<int> vc(lit);// 调用参数初始化列表进行初始化int arr[]{ 1,2,3,4,5 };
}
这两种写法看似,但是实际上底层是完全不同的两种实现的方式
decltype
// decltype的一些使用使用场景
template<class T1, class T2>
void F(T1 t1, T2 t2)
{decltype(t1 * t2) ret;cout << typeid(ret).name() << endl;
}void test6()
{const int x = 1;double y = 2.2;decltype(x * y) ret;decltype(&x) p;cout << typeid(ret).name() << endl;cout << typeid(p).name() << endl;F(1, 'a');
}
简单来说,就是可以把你要新定义的一个类型进行人为的定义,定义成一个你想让它变成的类型,使用场景也不算多,但是可以这样进行使用
左值引用和右值引用
首先要解决一个问题,什么是左值?
之前可能会说,左值就是等号左边的值,这肯定是不对的,左值是一个表示数据的表达式,可以获取它的地址,也可以进行赋值,通常来说它出现在赋值符号的左边,右值不能出现在赋值符号的左边,定义的时候,const修饰符修饰的变量不可以对它进行赋值,但是可以对它取地址,因此,可以说左值引用就是给左值的引用,给左值取别名
常见的左值
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;
常见的右值
10;
x + y;
fmin(x, y);
而对这些起别名就是右值引用
int&& rr1 = 10;
double&& rr2 = x + y;
double&& rr3 = fmin(x, y);
对于右值引用来说,可以理解为,右值本身是不能取地址的,但是给右值取别名之后,右值就会被存储到某些地方,此时就可以取到它的地址
左值引用只能引用左值,不能引用右值,如果想引用右值需要用const
int main()
{// 左值引用只能引用左值,不能引用右值。int a = 10;int& ra1 = a; // ra为a的别名//int& ra2 = 10; // 编译失败,因为10是右值// const左值引用既可引用左值,也可引用右值。const int& ra3 = 10;const int& ra4 = a;return 0;
}
move
右值只能引用右值,不能引用左值,但是右值可以引用move之后的左值
void test7()
{// 右值引用只能右值,不能引用左值。int&& r1 = 10;// error C2440: “初始化”: 无法从“int”转换为“int &&”// message : 无法将左值绑定到右值引用int a = 10;//int&& r2 = a;// 右值引用可以引用move以后的左值int&& r3 = std::move(a);
}
左右值引用的场景
那左右值引用能干啥呢?
左值引用
对比下面两种传参方式
void func(const string& str);
void func(string str);
从传参的效率上就不一样了,对于传引用来说,每次传参的代价是很低的,只需要把变量的地址给过去就可以了,但是对于传值来说就不一样了,传参的代价是相当高的,需要把原始的参数拷贝给新的值
也就是说,左值引用做参数减少了拷贝,提高效率的使用场景和价值
左值引用的缺陷
那左值引用有什么缺陷呢?
第一个是,当函数返回的对象是一个局部对象的时候,是不可以使用传引用返回的,因为这个变量出了作用域就被销毁了,因此不能使用传左值引用,只能进行传值返回,例如下面的场景
mystring::string to_string(int x){mystring::string ret;while (x){int val = x % 10;x /= 10;ret += ('0' + val);}reverse(ret.begin(), ret.end());return ret;}
此时的string是一个局部变量,如果使用传引用返回会访问一个不存在的地址,这是不被允许的,但如果采用传值返回,又会导致增加了拷贝构造的次数,并且可能还是两次
在新的编译器中,函数得到的这个string在返回的时候,会直接赋给新的值,调用一次拷贝构造,而在旧一点的编译器中,从函数的返回值会先拷贝构造一次到一个临时常量,再从这个临时常量拷贝构造一次到外部定义的string中
而使用移动构造,可以解决这个问题,编译器会默认使用最匹配的参数进行调用,因此会优先使用移动构造
搭配move函数
move函数的作用,就是单纯的把左值转换成右值引用,由此来实现移动语义
那这样有什么用呢?该如何理解这个意思呢?
如果有下面的代码:
string s2(s1)
这样的语句代表的含义是,调用拷贝构造,这里的s1是一个左值
但是如果要是改成这样
string s2(move(s1))
这样就不一样了,把s1放move函数中,这样就可以把s1当成一个右值,而右值是可以调用移动构造的,这样就可以不用调用拷贝构造浪费空间,而是可以直接的把值置换到我们所需要的s2里面,但是这样其实是不好的,这样会导致,虽然确实把s2的值填充了,但是却把s1的值架空了
简单来说,移动构造就是把资源全部偷过来,把原来的资源都架空
再举一个例子:
int main()
{
list<string> lt;
string s1("1111");
// 这里调用的是拷贝构造
lt.push_back(s1);
// 下面调用都是移动构造
lt.push_back("2222");
lt.push_back(std::move(s1));
return 0;
}
如果只是简单的调用s1,那么s1会被当成是一个左值,而左值会调用的是拷贝构造,但是如果把它强制转换成右值,那么就会调用的是移动构造,很明显,移动构造的使用成本是要比拷贝构造低很多的
万能引用和完美转发
前面关于右值引用中和前面有比较大不同的一点就是出现了&&符号,如果把这个符号看成是右值引用的标识符,也是不对的,C++11在模板中也新增了关于&&符号,这个符号代表的是万能引用,而不是右值引用,简单来说就是,既能接收左值也能接收右值
模板的万能引用只是提供了一个可以接收左值和右值的能力,一般来说是不可以两个都接收的
实际的使用中,引用类型的作用会限制接收的类型,会变成左值,而如果想要在传递的过程中保持右值的属性,就需要用到万能引用和完美转发
下面做一个实验来验证功能
void check(int& t)
{cout << "左值引用" << endl;
}void check(int&& t)
{cout << "右值引用" << endl;
}void check(const int& t)
{cout << "const左值引用" << endl;
}void check(const int&& t)
{cout << "const右值引用" << endl;
}void test8()
{const int a = 1;const int& b = 1;int c = 0;check(a);check(b);check(c);check(1);check(move(a));check(move(b));
}
结果也是符合预期的,把上述代码进行适当更改
void check(int& t)
{cout << "左值引用" << endl;
}void check(int&& t)
{cout << "右值引用" << endl;
}void check(const int& t)
{cout << "const左值引用" << endl;
}void check(const int&& t)
{cout << "const右值引用" << endl;
}void func1(int t)
{check(t);
}void test8()
{const int a = 1;const int& b = 1;int c = 0;func1(move(a));
}
此时运行结果是左值引用,这是为什么?其原因是进入func1函数后,函数参数就从右值变成左值了,此时它的右值属性就会消失,因此出现了下面的用法:
template<class T>
void func1(T&& t)
{check(t);
}
此时运行结果是const左值引用,这说明它保持了const属性,但是依旧没有保持右值的属性,右值的属性依旧被退化成左值了
再进行改良
template<class T>
void func1(T&& t)
{check(forward<T>(t));
}
此时运行结果就是const右值引用了,而新增的这个forward其实就是完美转发,它可以保障原来的属性,把原来这个值的属性转发出去,严格意义来说保持的是左值和右值,而如果没有万能引用运行结果依旧会丢失const属性
相关文章:

C++:C++11新特性---右值引用
文章目录 初始化方式显示查看类型initializer_listdecltype左值引用和右值引用move左右值引用的场景 万能引用和完美转发 本篇总结C11新特性 初始化方式 C11对参数列表的初始化有了更明确的定义,可以这样进行定义 // 列表初始化 void test1() {// 旧版本int x 0…...
计算机人机界面
人机界面是指入与机器之间相互交流和影响的区域。人机界面包括对数据和信息的输入和输出方法,以及人们对机器的操作和控制。早期,人机交互界面是控制合,随后通过键盘进行操作,目前为鼠标和键盘操作,而智能手机采用触摸…...

【BUG合集】(一)①数据库存1/0,请求结果返回true和false;②sql查数据库能查,但mybatis查为空;③data64图片存储为异常;
前言 最近,在工作上接手的任务中,各种 bug 问题出现,在解决的同时也可以记录一下。因此,觉得可以出个记录 bug 合集。方便后来者碰到类似情况,可以作为一个参考进行解决。 文章题目就包含当前文章内容中所遇到的三个 b…...

python基础练习题库实验7
文章目录 题目1代码实验结果题目2代码实验结果题目3代码实验结果题目总结题目1 编写代码创建一个名为Staff的类和方法__init__,以按顺序初始化以下实例属性: -staff_number -first_name -last_name -email 代码 class Staff:def __init__(self, staff_number, first_name,…...

C语言你爱我么?(ZZULIOJ 1205:你爱我么?)
题目描述 LCY买个n束花准备送给她暗恋的女生,但是他不知道这个女生是否喜欢他。这时候一个算命先生告诉他让他查花瓣数,第一个花瓣表示"爱",第二个花瓣表示"不爱",第三个花瓣表示"爱"..... 为了使最…...

动手学深度学习(三)---Softmax回归
文章目录 一、理论知识1.图像分类数据集2.softmax回归的从零开始实现3.Softmax简洁实现 【相关总结】torch.sum()torch.argmax()isinstance():[python] softmax回归 一、理论知识 回归估计一个连续值分类预测一个离散类别 回归单连续数值输出自然区间R跟真实值的区别作为损失 …...

爬虫代理技术与构建本地代理池的实践
爬虫中代理的使用: 什么是代理 代理服务器 代理服务器的作用 就是用来转发请求和响应 在爬虫中为何需要使用代理? 隐藏真实IP地址:当进行爬取时,爬虫程序会发送大量的请求到目标网站。如果每个请求都使用相同的IP地址ÿ…...

token认证机制,基于JWT的Token认证机制实现,安全性的问题
文章目录 token认证机制几种常用的认证机制HTTP Basic AuthOAuthCookie AuthToken AuthToken Auth的优点 基于JWT的Token认证机制实现JWT的组成认证过程登录请求认证 对Token认证的五点认识JWT的JAVA实现 基于JWT的Token认证的安全问题确保验证过程的安全性如何防范XSS Attacks…...

什么是计算机病毒?
计算机病毒 1. 定义2. 计算机病毒的特点3. 计算机病毒的常见类型和攻击方式4. 如何防御计算机病毒 1. 定义 计算机病毒是计算机程序编制者在计算机程序中插入的破坏计算机功能或者破坏数据,影响计算机使用并且能够自我复制的一组计算机指令或程序代码。因其特点与生…...

【C++】哈希(位图、布隆过滤器)
一、哈希的应用(位图和布隆过滤器) 1、位图(bitset) (1)位图概念 【题目】 给 40亿 个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这 40亿 个数中。…...

LeetCode198.打家劫舍
打家劫舍和背包问题一样是一道非常经典的动态规划问题,只要做过几道动态规划的题,这道题简直就非常容易做出来。我应该花了10来分钟左右就写出来了,动态规划问题最重要的就是建立状态转移方程,就是说如何从上一个状态转移到下一个…...

Appium PO模式UI自动化测试框架——设计与实践
1. 目的 相信做过测试的同学都听说过自动化测试,而UI自动化无论何时对测试来说都是比较吸引人的存在。相较于接口自动化来说,它可以最大程度的模拟真实用户的日常操作与特定业务场景的模拟,那么存在即合理,自动化UI测试自然也是广…...

使用VUE3实现简单颜色盘,吸管组件,useEyeDropper和<input type=“color“ />的使用
1.使用vueuse中的useEyeDropper来实现滴管的功能和使用input中的type"color"属性来实现颜色盘 效果: 图标触发吸管 input触发颜色盘 组件代码部分 :<dropper> ---- vueuse使用 <template><div class"sRGBHexWrap fbc…...
matlab提取特征(医学图像)
乳腺肿瘤图片提取特征: %形态特征 %周长 面积 周长面积比 高度 宽度 纵横比 圆度 矩形度 伸长度 拟合椭圆长轴长 拟合椭圆短轴长 %拟合椭圆长轴与皮肤所夹锐角 最小外接凸多边形面积 最小外接凸多边形面积与肿瘤区面积比 %小叶树 叶指数 %纹理特征 %方差 熵 最小边差异 四个方…...

P4 C++ 条件与分支(if)
前言 今天我们来看看条件语句,换句话说,也就是 if 语句、if else 和 else if 等等这写语句。 我知道大家基本上已经非常了解 if 语句和所有 C 中的分支语句,但我还是鼓励你们继续看完这一讲,这里可能包含一些新东西。我们还会深入…...

django+drf+vue 简单系统搭建 (4) 用户权限
权限控制是web中的重要组成部分。与以往的博客系统不同,本次工具页面仅支持注册用户。 每个注册用户都能访问到工具页面,并且提交自己的task来选择具体的工具来处理自己提交的文件。每个注册用户都只能访问到自己提交的task,而管理员则可以查…...

stm32 计数模式
计数模式 但是对于通用定时器而言,计数器的计数模式不止向上计数这一种。上文基本定时器中计数器的计数模式都是向上计数的模式。 向上计数模式:计数器从0开始,向上自增,计到和自动重装寄存器的目标值相等时,计数器清…...

rss服务搭建记录
layout: post title: RSS subtitle: vps搭建RSS服务 date: 2023-11-27 author: Sprint#51264 header-img: img/post-bg-universe.jpg catalog: true tags: - 折腾 文章目录 引言RSShub-dockerRSS-radarFreshrssFluent reader获取fever api配置Fluent Reader同步 结语 引言 一个…...

GEE 23:基于GEE实现物种分布模型之随机森林法
基于GEE实现物种分布模型之随机森林法 1.物种分布数据2.研究区绘制3.预测因子选择 1.物种分布数据 根据研究目的和需要导入物种数据: // Load presence data var Data ee.FeatureCollection("users/************736/Distribution"); print(Original da…...

HCIE 01:基于前缀列表的BGP ORF功能
当运行BGP协议的某台设备上,针对入方向配置了基于ip-prefix的路由过滤,过滤了邻居发送的路由; 目前想,通过在peer关系的两端设备上都配置ORF功能,实现路由发送端只能送路由接收端过滤后的路由; ORF功能的说…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...

Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...

Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...
标注工具核心架构分析——主窗口的图像显示
🏗️ 标注工具核心架构分析 📋 系统概述 主要有两个核心类,采用经典的 Scene-View 架构模式: 🎯 核心类结构 1. AnnotationScene (QGraphicsScene子类) 主要负责标注场景的管理和交互 🔧 关键函数&…...

免费批量Markdown转Word工具
免费批量Markdown转Word工具 一款简单易用的批量Markdown文档转换工具,支持将多个Markdown文件一键转换为Word文档。完全免费,无需安装,解压即用! 官方网站 访问官方展示页面了解更多信息:http://mutou888.com/pro…...

电脑定时关机工具推荐
软件介绍 本文介绍一款轻量级的电脑自动关机工具,无需安装,使用简单,可满足定时关机需求。 工具简介 这款关机助手是一款无需安装的小型软件,文件体积仅60KB,下载后可直接运行,无需复杂配置。 使用…...