【C++11】initializer_list | 右值引用 | 完美转发

一切皆可列表{ }初始化

在C++98,允许花括号{ } 对数组、结构体类型初始化。

class Data
{
public:Data(int y, int m, int d):_y(y), _m(m), _d(d){}
private:int _y;int _m;int _d;
};int arr[4]={0,1,2,3};//列表初始化
Data d1={2024,03,21};//列表初始化 

C++11允许通过{ } 初始化内置类型或者用户自定义类型。同时支持省去赋值=符号

class Data
{
public:Data(int y, int m, int d)  :_y(y), _m(m), _d(d){}
private:int _y;int _m;int _d;
};int main()
{int a = 1;int b = { 1 };//支持列表初始化int c{ 1 };   //支持列表初始化,同时省略=Data d1(2024, 03, 21);Data d2={ 2024, 03, 21 };//支持列表初始化Data d3{ 2024, 03, 21 };//支持列表初始化,同时省略=Data* p1=new Data[]{{2023,03,21},{2023,03,22},{2023,03,23}};return 0;
}

创建d2时,会先调用{2024 ,03,21}列表构造出一个临时对象,再用临时对象拷贝构造d2。

如何证明?对列表的对象取别名,只有加const后才能通过。

编译器一般将 构造+拷贝构造优化成—>直接构造


std::initializer_list

在C++11中,std::initializer_list是一个模板类,它用于表示初始化列表。

当编译器遇到一个使用花括号{}的初始化列表时,它会尝试构造一个std::initializer_list对象,并将该对象传递给接受std::initializer_list参数的函数或构造函数。

initializer_list类中存在俩个指针,begin和end。

initializer_list同时支持迭代器

	initializer_list<int> il{ 1,2,3,4 };initializer_list<int>::iterator it = il.begin();while (it != il.end()){cout << *it << " ";++it;}

在C++11往后的各种容器中,都支持initializer_list构造

	vector<int> v1{ 1,2,3,4 };vector<string> v2{"apple","map","cat"};

 

initializer_list去构造vector的原理 

vector(initializer_list<T> it)
{reserve(it.size());for (auto& e : it){push_back(e);}
}

initializer_list的数据是放在常量区,不可修改 


auto自动推演

对于较长的类型,写起来比较复杂,就要auto帮助自动推演。

map<string, string> dict = { { "sort", "排序" }, { "insert", "插入" } };
//map<string, string>::iterator it = dict.begin();
auto it = dict.begin();  //简化代码

decltype

将对象声明为指定的类型;

typeid().name返回一个字符串,字符串的内容是类型。一般用于打印。

	int x = 1;double y = 3.14;decltype(x * y) ret;cout << "typeid(ret).name():" << typeid(ret).name()<< endl;


新容器

array

是一个静态数组,内存是放在栈上的。

array有俩个模板参数,第一个模板参数是类型,第二个是大小

array的设计初心是为了代替数组,因为数组的越界检查不严格,因此array是严格的断言

但是在日常的使用,完全可以用vector代替。

int main()
{array<int, 10> a1;   //定义一个可存储10个int类型元素的array容器array<double, 5> a2; //定义一个可存储5个double类型元素的array容器return 0;
}

forward_list容器

forwar_list是一个单链表

在实际使用,forward_list的运用少于list

  • forward_list只支持头插头删,尾插尾删的复杂度是O(N);
  • forward_list支持inset_after,插入的时间复杂度是O(N);
  • 删除指定元素要找前一个结点。复杂度是O(N);

unordered_map和unordered_set容器

底层是哈希表实现的map和set


右值引用

什么是左值?

数据的表达式,通常出现在等号的左边,是可以被取地址的。

	int a = 1;int* b = new int;const int c = 2;int d = a; //d也是左值

什么是右值?

字母常量,表达式的返回值,函数的返回值,通常出现在等号的右边

是不能被取地址的;

	10;		//常量Add(10, 5);//函数返回值5 + 1;	//表达式返回值
  • 右值的本质是一块临时变量,没有被存储起来,即将被销毁的。因此无法取到地址。
  • 值得注意的是,函数的返回值如果返回的是一块实际存储的空间,那么就是不是右值。

 左值引用和右值引用

在C++11新特性后,增加了右值引用的玩法。

左值就是给左值取别名,右值就是给右值取别名。本文着重介绍右值。

右值引用的符号  (类型&&)

	10;		//常量Add(10, 5);//函数返回值5 + 1;	//表达式返回值int&& rp1 = 10;int&& rp2 = Add(10, 5);int&& rp3 = 5 + 1;

注意:
一个右值被取别名后,就被存储到特定的位置上,就能通过别名修改右值的内容;

左值引用可以引用右值吗?

不能。左值是可以被修改的,右值是常量不可被修改。将右值给左值引用,涉及权限的放大。

给左值引用加上const后,就能引用右值。

	int& rp = Add(10, 5);//出错const int& rp = Add(10, 5);//正常

右值引用可以引用右值吗?

右值引用只能引用右值。

右值引用可以引用move后的左值。

	10;//右值int i = 10;//左值int&& r = move(i);

主要原因:

  1. 语义不匹配:右值引用的设计初衷是为了支持移动语义,即从一个临时对象(右值)中“窃取”资源并转移到另一个对象。左值通常具有持久的存储位置,因此将其与移动语义相关联是不合适的。
  2. 避免意外行为:如果允许右值引用引用左值,那么开发者可能会不小心将左值当作右值来处理,从而导致资源被错误地移动而不是复制。这可能导致程序出现难以调试的错误。

move是一种资源转移,对于左值的资源转移,要非常的谨慎! 


右值引用的场景

移动构造函数和移动赋值运算符

就拿模拟实现的to_string函数的来说明

To_string函数体中的str是一个左值,出了函数作用域,就会被销毁。我们把这个即将销毁的值叫做 “将亡值” 。

这一条语句的执行过程是:str先构造出一个临时对象,再用临时对象拷贝构造出s对象(如果考虑优化,编译器会直接用str构造出s对象)

本文默认不考虑编译器的优化

如果str出了作用域就会被销毁,那么他的资源就被释放,反而重新拷贝出一份一模一样的资源,这是浪费效率的事情,如果在此时发生深拷贝,那么效率会更低。

		string(string&& s):_str(nullptr), _size(0), _capacity(0){cout << "string(string&& s) -- 移动构造" << endl;swap(s);}

移动构造是一种转移资源!


移动赋值

移动赋值同样也是一种转移的思想。

		string& operator=(string&& s){cout << "string& operator=(string&& s) -- 移动赋值" << endl;swap(s);return *this;}

对于将亡值,编译器会优先调用移动拷贝和移动赋值。


右值通过move引用左值

通过move函数后,s1会被当成右值,调用移动构造函数,会将s1的资源转移到s2上,s1的内容会变为空。

总结:将亡值会调用移动构造和移动赋值来实例化对象

左值可以通过move转移资源,来调用移动构造和移动赋值。


万能引用

万能引用是指在模板中,即可以接收左值又可以接收右值。

template<class T>
void Fun(T&& x) //万能引用
{cout << x << endl;
}int main()
{Fun(10);//传入右值int i = 1;Fun(i);//传左值return 0;
}

调用模板函数,传入左值和右值都能被Fun函数接收,故针对模板类的&&是万能引用

右值引用的属性是什么?

void Func(int& x)
{cout << "左值引用" << endl;
}
void Func(const int& x)
{cout << "const 左值引用" << endl;
}
void Func(int&& x)
{cout << "右值引用" << endl;
}
void Func(const int&& x)
{cout << "const 右值引用" << endl;
}
template<class T>
void PerfectForward(T&& t)
{Func(t);
}
int main()
{int a = 10;PerfectForward(a);       //左值PerfectForward(move(a)); //右值const int b = 20;PerfectForward(b);       //const 左值PerfectForward(move(b)); //const 右值return 0;
}

左值和右值都会被万能引用接收,而后非const调用的Func函数是左值引用。

const调用的Func函数是右值引用。

说明右值被右值引用接收后的属性是左值!

针对这一点需要注意的,假如模拟实现的vector容器push_back接收到右值,调用inset()函数(同样实现了右值版本),却发现调不动,因为右值被引用后的结果是左值。

要让insert也调用右值,就必须先move再调用insert。


完美转发

完美转发(Perfect Forwarding)是一种技术,它允许函数模板将其参数无损地转发给另一个函数,保持参数的原始值类别(lvalue或rvalue)和类型。这通常用于编写通用包装器或代理函数,例如标准库中的 std::forward 和 std::tie

template<class T>
void PerfectForward(T&& t)
{Func(std::forward<T>(t));
}

有了完美转发之后,就不用担心出现移动构造+赋值的情况,就会出现移动构造+移动赋值,大大减小了资源的利用。

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

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

相关文章

云数据库价格一瞥(华为云、百度智能云、腾讯云、阿里云)

最近&#xff0c;大家似乎和价格“磕”上了。本文仅考虑主流产品&#xff08; RDS MySQL、Redis &#xff09;的部分主流规格&#xff0c;对各家厂商的价格做一个对比&#xff0c;供参考。 TL;DR&#xff1a; 总体来看&#xff0c;各家云厂商价格趋于持平&#xff0c;部分主流商…

创建一个qt登录界面,密码账号正确转到窗口2,否则弹出对话框提示账号密码错误,窗口2有四个按键,三个按键可以朗读按键文本,第四个退出。

作业要求&#xff1a; 主函数&#xff1a; int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();Form1 f;//连接窗口1的信号函数和窗口2打开的lambda函数Widget::connect(&w,&Widget::login,[&](){f.show();});return a.exec(); }窗…

无影云电脑不能连接到本机的调试串口的解决方案

目录 概述 解决方案 云端电脑中的操作 本地USBDK驱动程序的更新 概述 我从1月份开始使用阿里的无影云电脑进行嵌入式开发板的测试&#xff0c;主要的原因有两个&#xff1a;一是平时使用的笔记本资源过于紧张&#xff0c;二是方便移动办公&#xff0c;这样我只要平时拿着开…

解锁阿里巴巴1688数据宝藏:API助力批量获取商品价格、标题、图片及库存

在数字化时代&#xff0c;数据已成为商业决策的重要依据。对于电商从业者来说&#xff0c;掌握商品的价格、标题、图片及库存等关键信息&#xff0c;是优化销售策略、提升竞争力的关键。阿里巴巴1688平台作为国内领先的B2B电商平台&#xff0c;其海量的商品数据为商家提供了丰富…

DRF的认证、权限、限流、序列化、反序列化

DRF的认证、权限、限流、序列化、反序列化 一、认证 1、直接用&#xff0c;用户授权 实现方法 编写 ->认证组件 应用组件 编写 ->认证组件 from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationF…

基于opencv的视觉巡线实现

前言 这段时间在和学弟打软件杯的比赛&#xff0c;有项任务就是机器人的视觉巡线&#xff0c;这虽然不是什么稀奇的事情&#xff0c;但是对于一开始不了解视觉的我来说可以说是很懵了&#xff0c;所以现在就想着和大家分享一下&#xff0c;来看看是如何基于opencv来实现巡线的…

34. UE5 RPG实现鼠标点击移动

在前面&#xff0c;我们实现过使用键盘按键wasd去实现控制角色的移动&#xff0c;现在&#xff0c;我们实现了InputAction按键触发&#xff0c;后面&#xff0c;实现一下通过鼠标点击地面实现角色移动。 我们将实现两种效果的切换&#xff0c;如果你点击地面快速松开&#xff0…

LeetCode 289.生命游戏————2024 春招冲刺百题计划

根据 百度百科 &#xff0c; 生命游戏 &#xff0c;简称为 生命 &#xff0c;是英国数学家约翰何顿康威在 1970 年发明的细胞自动机。 给定一个包含 m n 个格子的面板&#xff0c;每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态&#xff1a; 1 即为 活细胞 &am…

鹅厂实习offer

#转眼已经银四了&#xff0c;你收到offer了吗# 本来都打算四月再投实习了&#xff0c;突然三月初被wxg捞了&#xff08;一年前找日常实习投的简历就更新了下&#xff09;&#xff0c;直接冲了&#xff0c;流程持续二十多天&#xff0c;结果是运气还不错&#xff0c;应该是部门比…

2024年光学通信和物联网、自动化控制和大数据国际会议(OCITACB2024)

2024年光学通信和物联网、自动化控制和大数据国际会议(OCITACB2024) 会议简介 2024年国际光通信与物联网、自动控制和大数据会议&#xff08;OCITACB2024&#xff09;的主要目标是促进光通信与物联网、自动管理和大数据领域的研发活动。另一个目标是促进研究人员、开发人员、工…

用three.js做一个3D汉诺塔游戏(下)

为桌台添加材质纹理 为物体添加适当的材质纹理,可以使其视觉效果产生质的飞跃。接下来,我们将为桌台添加一种木质纹理,用到的纹理贴图来自Pixabay.com。 我们使用 TextureLoader 来加载纹理贴图,其 load 方法第1个参数为贴图的 URL 字符串,该方法返回一个纹理对象,可直…

Linux服务器上搭建深度学习环境(安装anaconda、创建虚拟环境、安装pytorch)

Linux服务器的搭配 Linux服务器上安装anaconda创建虚拟环境linux上安装pytorchxshell连接服务器 Linux服务器上安装anaconda 链接 创建虚拟环境 参考教程&#xff1a;此处 linux上安装pytorch 链接 xshell连接服务器 链接

科技动态人工智能应用太空探索生物科技

根据最新的科技资讯&#xff0c;以下是一些值得关注的科技动态&#xff1a; 人工智能领域 智能体热潮 &#xff1a;随着大模型的研发热潮&#xff0c;AI智能体的发展迅速&#xff0c;它们被用作认知核心&#xff0c;具备强大的学习和迁移能力。智能体的架构和交互方式也在不断进…

python课后习题三

题目&#xff1a; 解题过程&#xff1a; 模式A&#xff1a; num int(input("&#xff08;模式A&#xff09;输入数字&#xff1a;")) for i in range(num): for j in range(num): if j < i 1: …

MQ的延迟队列

1&#xff0c;场景 1.定时发布文章 2.秒杀之后&#xff0c;给30分钟时间进行支付&#xff0c;如果30分钟后&#xff0c;没有支付&#xff0c;订单取消。 3.预约餐厅&#xff0c;提前半个小时发短信通知用户。 A -> 13:00 17:00 16:30 延迟时间&#xff1a; 7*30 * 60 * …

Excel·VBA考勤打卡记录整理

看到一个帖子《excel吧-考勤一天四次打卡&#xff0c;快速找出缺卡》&#xff0c;每个人每天有4次打卡记录&#xff0c;需要整理出所有缺少的打卡记录 与之前的文章《ExcelVBA考勤打卡记录统计结果》结果形式类似 与之前的文章《ExcelVBA考勤打卡记录数据整理》查找上下班打卡…

Linux、Docker、Brew、Nginx常用命令

Linux、Docker、Brew、Nginx常用命令 Linuxvi编辑器文件操作文件夹操作磁盘操作 DockerBrewNginx参考 Linux vi编辑器 Vi有三种模式。命令模式、输入模式、尾行模式&#xff0c;简单的关系如下&#xff1a; i -- 切换到输入模式&#xff0c;在光标当前位置开始输入文本。&a…

【go从入门到精通】初识struct结构体

作者简介&#xff1a; 高科&#xff0c;先后在 IBM PlatformComputing从事网格计算&#xff0c;淘米网&#xff0c;网易从事游戏服务器开发&#xff0c;拥有丰富的C&#xff0c;go等语言开发经验&#xff0c;mysql&#xff0c;mongo&#xff0c;redis等数据库&#xff0c;设计模…

虚拟网络设备性能优化

在现代网络架构中&#xff0c;虚拟网络设备扮演着越来越重要的角色&#x1f310;&#xff0c;特别是在云计算☁️和容器化技术&#x1f4e6;广泛应用的背景下。虚拟网络设备如虚拟以太网设备&#xff08;veth&#xff09;、虚拟交换机&#xff08;vSwitch&#xff09;、和虚拟路…

适用于 Mac 的 10 大数据恢复工具,具有优点、缺点

数据丢失很常见&#xff0c;并且可能由于许多不同的原因而发生。这种情况在我和我们团队的其他成员身上发生过很多次&#xff0c;即使我们格外小心我们的个人存储设备。 幸运的是&#xff0c;数据恢复软件在大多数情况下都可以工作。但是&#xff0c;由于数据丢失场景彼此之间…