C++学习记录——이십오 C++11(1)

news2024/12/27 16:08:08

文章目录

  • 1、列表初始化
  • 2、声明
    • decltype
  • 3、STL新容器
    • 小总结
  • 4、右值引用
    • 1、概念
    • 2、使用场景(包含移动构造)
    • 3、完美转发
    • 4、移动赋值
    • 5、C++98的const引用延长生命周期


1、列表初始化

大括号{}来代替初始化,并且是所有类型。

struct ZZ
{
	int _x;
	int _y;
};

int main()
{
	int x1 = 1;
	int x2 = { 2 };
	int x3{ 3 };
	int arr1[5]{ 0 };
	int arr2[]{ 1, 2, 3, 4, 5 };
	ZZ z{ 4, 7 };
	int x4(4);//调用了int的构造
	int* pa = new int[4]{ 0 };
	return 0;
}

像类的初始化写法,加=相当于构造函数初始化+拷贝构造然后优化成直接构造。

vector<int> v1 = { 1, 2, 3, 4, 5 };//原写法
vector<int> v1{ 1, 2, 3, 4, 5 };//C++11写法

11支持这样写,实际上这里是把v1当成了initializer_list的类。这样写auto v = { 1, 2, 3, 4, 5 },然后用typeid(v).name()就可以看到它的类型。展开写的话就是initializer_list< int > it1 = { 1, 2 }。在这个系统带的类里也有迭代器,不能修改,它指向的内容在常量区,begin和end返回是头地址和尾地址下一位。在vector写入这样类型的初始化可以这样写

vector(initializer_list<T> il)
{
	for (auto& e : il)
	{
		push_back(e);
	}
}

或者用迭代器也可以。

	Date d1(2023, 5, 23);
	Date d2(2023, 5, 24);
	vector<Date> v1 = { d1, d2 };
	vector<Date> v2 = { Date d1(2023, 5, 23), Date d2(2023, 5, 24) };
	vector<Date> v3 = { {2023, 5, 23 }, { 2023, 5, 24 } };

三个初始化都行,这时候会被当作是initializer_list< Date >。

2、声明

auto就是其中之一,自动推演变量类型。

decltype

	const int x = 1;
	double y = 2.2;
	decltype(x * y) ret;//ret类型就是double
	decltype(&x) tmp;//tmp类型就是const int*
	vector<decltype(x * y)> v;

它可以推导表达式类型,用这个类型去实例化模板参数或者定义对象。

还有C++中nullptr的引入。

范围for循环已经用过,智能指针之后写

3、STL新容器

在这里插入图片描述

array,forward_list,两个新map和set,但是前两个很鸡肋。array是固定大小的静态数组,用vector更舒服;另外一个是在需要单链表头插的时候很适合,其他都不算好,相比list每个结点可以节省一个指针的空间,头插头删时用它可以。

小总结

增加支持initializer_list的构造函数,使用更方便,有一定价值
增加cbegin和cend系列迭代器接口,也有点鸡肋
移动构造和移动赋值,提高了拷贝效率(之后写),重要
支持右值引用相关插入接口函数,提高了拷贝效率,重要

4、右值引用

1、概念

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋
值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左
值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。

	int* p = new int(0);
	int b = 1;
	const int c = 2;

p,b,c,*p都是左值。

右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能
取地址
。右值引用就是对右值的引用,给右值取别名。

在这里插入图片描述

	int* p = new int(0);
	int b = 1;
	const int c = 2;

	int& ret1 = b;
	const int& ret2 = b + c;
	int&& ret3 = b + c;
	int&& ret4 = b;//错误

右值引用符号是&&。上面四个就是左/右值引用分别给左/右值取别名,左值引用如果不加const就给右值取别名那就是权限放大,所以必须加const才能通过;右值引用不能给左值取别名,所以ret4那里出错。

在这里插入图片描述
但是这样写就可以int&& ret4 = move(b);

  1. 左值引用只能引用左值,不能引用右值。
  2. 但是const左值引用既可引用左值,也可引用右值。
  3. 右值引用只能右值,不能引用左值。
  4. 但是右值引用可以move以后的左值。

2、使用场景(包含移动构造)

void func(int& a)
{
	cout << a << endl;
}

void func(int&& a)
{
	cout << a << endl;
}

int main()
{
	int a = 0;
	int b = 1;
	func(b);
	func(a + b);
	return 0;
}

虽然可以变成const int& a,来传入左右值,但是进入函数内部还是无法区分左右值,所以就可以这样写成函数重载。之所以要区分左右值,是因为内置类型不需要分,但是自定义类型需要考虑。我们可以用自己造的string类。

	string s1("hello");
	string ret1 = s1;
	string ret2 = (s1 + '!');

如果这两个都是深拷贝,代价有点高。所以类里就得做一个函数重载

string(string&& s)
	:_str(nullptr)
{
	swap(s);
}

这个接收右值的就是移动构造。深拷贝相当于两个空间,那么为了减少代价,就不另外开辟空间,让新变量指向这个空间,替换掉旧变量。move的作用则是把s1指向的内容给拿走,s1连同之前的空间废掉,交给其他变量。move是一个函数调用,返回的是右值。所以右值引用的移动构造效率比较高,它是不动空间,动指向空间的东西。

左值引用直接减少了拷贝,用的是引用传参和传引用返回。但是有些场景不能用引用返回,比如函数内的局部对象,否则就会有一些强行的拷贝。

C++中传值返回拷贝比较多,有些场景是不可避免的右值返回。编译器在这里做了很多复杂的操作。这里就不展开写了。

11之后所有STL容器都增加了移动构造,不仅是构造,插入接口也都增加了右值引用。很多原先对于右值只能深拷贝,现在就改成移动构造来提高效率。

匿名对象被认为是右值,直接传的字符串会被认为是右值。如果没有右值引用,两个就都是深拷贝。

左/右值引用都减少拷贝。左值引用是直接,右值引用是间接,先识别是不是右值,是的话就不再深拷贝,转为移动拷贝,移动拷贝效率高。移动拷贝就是直接移动资源。

右值不能取地址,不能修改,右值取别名后会右值会被存储到特定位置。int&& r1 = 10,10不能被取地址,但是r1可以取地址,可以修改数值,所以r1是左值,如果前面加上const,那就不能修改,右值引用的const就只是const作用,但是左值引用+const,也就是const int&这样的,就可以左右值都能引用。

对于那些具有常性的变量(比如临时变量)是不能被修改的,比如string& s3 = s1 + s2,这里就会报错,但是如果去掉引用就可以了,但是去掉引用后s1 + s2可以修改?是不是有点不太正常?这是因为传到移动构造后,传进来的是右值,传出去的时候就变成左值了。所以右值引用引用后属性是左值,这样才能实现资源转移。

3、完美转发

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<typename T>
void PerfectForward(T&& t)//引用折叠、万能引用,左右值都能传
{
	Fun(t);//Fun(forward<T>(t));
}
int main()
{
	PerfectForward(10); // 右值
	int a;
	PerfectForward(a); // 左值
	PerfectForward(std::move(a)); // 右值
	const int b = 8;
	PerfectForward(b); // const 左值
	PerfectForward(std::move(b)); // const 右值
	return 0;
}

借助模板的推导,如果传左值,就会自动推导成T&,右值就是&&。这个代码就传给PerfectForward,然后Fun再传递一层。

在这里插入图片描述

要右值引用的话,是把参数类型换成右值引用就可以了吗?在类里面保证这点的话,比较麻烦,需要改很多,比如往一个函数里传右值,但是这个函数还需要把这个值传给别的函数,还得换成左值,所以要保证整个链路都是右值才行。各个函数都增加右值引用的函数,函数括号里的参数,传到函数内部用来赋值等操作都会引起右值转为左值。但是即使全改成右值也不行,需要有别的措施来保证右值。

为什么会成为左值?其实是因为这个右值转左值转早了,Fun(t)那里传的就已经全是左值了,在一个个函数传参数时很有可能会不在合适的地方转成左值,用Fun(forward< T >(t))可以保持右值,这也就是完美转发。

左值引用已经能解决大部分问题,不过它没解决的问题就是局部对象返回问题和插入接口、对象拷贝问题。比如自定义类型的局部变量/对象的返回,这一直是一个不好解决的问题。浅拷贝的类,像日期类,那么就用拷贝构造,如果是深拷贝,那就是移动构造,移动构造可以转移右值,因为它没有拷贝,只有移动资源,效率更高。

类里还是要有右值引用的版本,编译器会找最合适的函数来运行代码。

4、移动赋值

函数返回值时,会进行两次深拷贝,其实应当是一次拷贝构造,一次拷贝赋值,相对应的就有移动构造和移动赋值。返回局部变量时,它会优化成移动构造+移动赋值,就不是两个拷贝了。

右值引用借助移动语义来改善自定义类型的深拷贝问题。

string& operator=(string&& str)//移动赋值
string& operator=(const string& str)/拷贝赋值

移动赋值是如何实现的?比如s = t,t是一个右值,马上要结束生命周期了,那么移动赋值会把t的内容和s的内容直接换过来,这样s里面就是t的内容了,t里面就是s的内容了,t带着s的内容析构,那么移动赋值就完成了。

5、C++98的const引用延长生命周期

const string& ret1 = string("hello world");

没有右值引用的时候,就用这种方法来完成临时变量的生命周期延长,但这种方法有缺陷,但是当出了这个类,析构后还是不见了,想用类外的函数来使用类内的东西就不行了。

如果类外的函数不是引用类型的,它返回的值会是一个临时变量,如果用引用类型的变量来接收肯定就不行,但加了一个const就可以了,并且这个临时变量也确实延长周期了。

本篇gitee

结束。

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

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

相关文章

RabbitMQ---订阅模型-Fanout

1、 订阅模型-Fanout Fanout&#xff0c;也称为广播。 流程图&#xff1a; 在广播模式下&#xff0c;消息发送流程是这样的&#xff1a; 1&#xff09; 可以有多个消费者 2&#xff09; 每个消费者有自己的queue&#xff08;队列&#xff09; 3&#xff09; 每个队列都要绑定…

记录 JSONObject.parseObject json对象转换 对象字段为null

1.业务背景 使用websocket 接收消息都是String类型&#xff0c;没办法自定义实体类接收&#xff0c;所以接发都必须将json 转 对象 对象转 json。 这是我最开始的实体类&#xff0c;也就是转换的类型 package com.trinity.system.domain;import lombok.AllArgsConstructor; im…

浏览器跨域

生活中的事跟跨域有什么关系&#xff0c;那必须有。 跨域的产生是浏览器的安全机制引起的&#xff0c;只有在使用Ajax时才会发生。简单来说就是你可以通过ajax发送请求&#xff0c;但要看远程服务器脸色&#xff0c;他没授权&#xff0c;浏览器这个老六就给拦截了&#xff0c;不…

Java之ApI之Math类详解

1 Math类 1.1 概述 tips&#xff1a;了解内容 查看API文档&#xff0c;我们可以看到API文档中关于Math类的定义如下&#xff1a; Math类所在包为java.lang包&#xff0c;因此在使用的时候不需要进行导包。并且Math类被final修饰了&#xff0c;因此该类是不能被继承的。 Math类…

6.基于二阶锥规划的主动配电网最优潮流求解

matlab代码&#xff1a; 6.基于二阶锥规划的主动配电网最优潮流求解 参考文献&#xff1a;主动配电网多源协同运行优化研究_乔珊 摘要&#xff1a;最优潮流研究在配 电网规划运行 中不可或缺 &#xff0c; 且在大量分布式能源接入 的主动配 电网环境下尤 为重要 。传统的启发…

Spring 与【MyBatis 】和【 pageHelper分页插件 】整合

目录 一、Spring整合MyBatis 1. 导入pom依赖 2. 利用mybatis逆向工程生成模型层层代码 3. 编写配置文件 4. 注解式开发 5. 编写Junit测试类 二、AOP整合pageHelper分页插件 1. 创建一个AOP切面 2. Around("execution(* *..*xxx.*xxx(..))") 表达式解析 3. 编…

Java IDEA Web 项目 1、创建

环境&#xff1a; IEDA 版本&#xff1a;2023.2 JDK&#xff1a;1.8 Tomcat&#xff1a;apache-tomcat-9.0.58 maven&#xff1a;尚未研究 自行完成 IDEA、JDK、Tomcat等安装配置。 创建项目&#xff1a; IDEA -> New Project 选择 Jakarta EE Template&#xff1a;选择…

一文了解SpringBoot中的Aop

目录 1.什么是Aop 2.相关概念 3.相关注解 4.为什么要用Aop 5.Aop使用案例 1.什么是Aop AOP&#xff1a;Aspect Oriented Programming&#xff0c;面向切面&#xff0c;是Spring三大思想之一&#xff0c;另外两个是 IOC-控制反转 DI-依赖注入 (Autowired、Qualifier、Re…

LabVIEW开发灭火器机器人

LabVIEW开发灭火器机器人 如今&#xff0c;自主机器人在行业中有着巨大的需求。这是因为它们根据不同情况的适应性。由于消防员很难进入高风险区域&#xff0c;自主机器人出现了。该机器人具有自行检测火灾的能力&#xff0c;并通过自己的决定穿越路径。 由于消防安全是主要问…

JAVA设计模式第十二讲:大厂实践 - 美团: 设计模式二三事

JAVA设计模式第十二讲&#xff1a;大厂实践 - 美团: 设计模式二三事 设计模式是众多软件开发人员经过长时间的试错和应用总结出来的&#xff0c;解决特定问题的一系列方案。现行的部分教材在介绍设计模式时&#xff0c;有些会因为案例脱离实际应用场景而令人费解&#xff0c;有…

windows上sqlserver的ldf日志文件和数据mdf文件分别放到不同的磁盘

之前我的windows上已安装好了sqlserver2017&#xff0c;有一个名为TestDb的数据库。ldf文件和mdf文件都一起放在D:\Database目录下。现在需要把ldf日志文件到E盘的database目录下。 重要的事情先说三遍 先停止网关&#xff08;例如nginx&#xff09;并备份数据库 先停止网关&am…

2023泉城杯 easy_log的解题

压缩包解压里面是一个 access.log 日志文件。 捋数据 进行过远程命令执行 这个后续没啥用 可疑字符串 可疑字符串/upload/ma.php?logvar_dump(%27cGFzc3dvcmQ6IHNAZncjdiVmOQ%27);这个首先就判断是不是base64编码&#xff08;英文大小写、数字和、/&#xff09;以及用作后缀…

深度学习:Sigmoid函数与Sigmoid层区别

深度学习&#xff1a;Sigmoid函数与Sigmoid层 1. Sigmoid神经网络层 vs. Sigmoid激活函数 在深度学习和神经网络中&#xff0c;“Sigmoid” 是一个常见的术语&#xff0c;通常用来表示两个相关但不同的概念&#xff1a;Sigmoid激活函数和Sigmoid神经网络层。这两者在神经网络…

【广州华锐互动】VR高校虚拟实验教学平台提供丰富的资源支持,提高教学效果

随着科技的不断进步&#xff0c;虚拟现实(VR)技术已经逐渐渗透到各个领域&#xff0c;其中包括教育。 广州华锐互动利用VR虚拟现实技术打造的VR高校虚拟实验教学平台&#xff0c;是一种新型的教学工具&#xff0c;它提供了一个在线的教学资源管理平台&#xff0c;包含教学平台、…

homeassistant ubuntu自启动 网络设置

命令行安装virtualbox 或者安装包 hass官网下载 haos_ova-10.4.vdi virtualbox 装hass 最少2G内存 其他省略 自启动&#xff1a; gnome-session-properties 添加 VBoxManage startvm hass --type headless hass为自己的虚拟机名字 网络配置如下&#xff1a; 要全部打开

在 AWS 中导入 qcow2 镜像

文章目录 在 AWS 中导入 qcow2 镜像使用的格式和问题步骤概述前提条件转换镜像格式并上传至 S3创建角色并配置策略策略文件内容创建container.json配置文件导入镜像创建 AMI 并启动实例参考:在 AWS 中导入 qcow2 镜像 当我们在多云环境中部署应用时,有时候可能需要把基于 qem…

Python爬虫 异步、缓存技巧

在进行大规模数据抓取时&#xff0c;Python爬虫的速度和效率是至关重要的。本文将介绍如何通过异步请求、缓存和代理池等技巧来优化Python爬虫的速度和性能。我们提供了实用的方案和代码示例&#xff0c;帮助你加速数据抓取过程&#xff0c;提高爬虫的效率。 使用异步请求、缓…

LeetCode560.和为k的子数组

这道题我用的是暴力法&#xff0c;当然也是不断的提交不断发现问题改出来的&#xff0c;比如我之前是算到和大于目标值就break&#xff0c;其实不行因为后面还可以有负数&#xff0c;我把break删了。后面和为目标之后就答案1然后break然后下一次遍历&#xff0c;测试用例中就出…

Web服务器端应用开发

一、登录验证器 1.1相关概念 登录验证器是一种用于提高帐户安全性的应用或设备&#xff0c;它可以在你输入用户名和密码后&#xff0c;生成或接收一个一次性的验证码或通知&#xff0c;以进行第二次身份验证。这样&#xff0c;即使你的密码被泄露或破解&#xff0c;其他人也无…

大模型是什么?泰迪大模型能够解决企业哪些痛点?

什么是大模型&#xff1f; 大模型是指模型具有庞大的参数规模和复杂程度的机器学习模型。在深度学习领域&#xff0c;大模型通常是指具有数百万到数十亿参数的神经网络模型。这些模型需要大量的计算资源和存储空间来训练和存储&#xff0c;并且往往需要进行分布式计算和特殊…