C++ - C++11历史 - 统一列表初始化 - aotu - decltype - nullptr - C++11 之后 STL 的改变

news2024/11/18 5:50:52

C++的发展史了解

在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称。

不过由于C++03(TC1)主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。从C++0x到C++11,C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟。

相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。

相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多,所以我们要作为一个重点去学习。
C++11 - cppreference.com

 而 C++ 11 并不是一蹴而就的,1998年是C++标准委员会成立的第一年,本来计划以后每5年视实际需要更新一次标准,C++国际标准委员会在研究C++ 03的下一个版本的时候,一开始计划是2007年发布,所以最初这个标准叫C++ 07。

但是到06年的时候,官方觉得2007年肯定完不成C++ 07,而且官方觉得2008年可能也完不成。

最后干脆叫C++ 0x。x的意思是不知道到底能在07还是08还是09年完成。结果2010年的时候也没完成,最后在2011年终于完成了C++标准。所以最终定名为C++11。

 统一列表初始化

 {}初始化

 列表初始化,C 当中的列表初始化,支持的是 数组的列表初始化,在 C++11 之后,支持对 struct (结构体)。

这里的 列表初始化 和 构造函数当中的 初始化列表是两个语法,是不一样的,这里要区分开来。

struct point
{
	point(int x, int y)
		:_x(x)
		, _y(y)
	{}

	int _x;
	int _y;
};


int main()
{
    // 这三种方式都可以
	point p0(0, 0);
	point p1 = { 0, 0 };
	point p2{0, 0};
}

 上述在主函数使用三种方式构造的 point 的对象,都是要调用其中的构造函数的,所以上述三种方式是等价的。

其实,point p1 = { 0, 0 }; 这种方式其实是一种 多参数的 隐式类型转换,而像 string str = "xxxx"; 这样的方式是一种 单参数的隐式类型转换。

 验证多参数的隐式类型转换:

	point& r = { 1,2 };      // 编译报错
	const point& r = { 1,2 }; // 编译通过

之所以出现上述的情况,是因为 发生了隐式类型的转换,发生隐式类型的转换要 先根据其他类型来临时对象,然后在使用拷贝构造函数 构造 出我们想要的对象。而上述两种方式是使用 引用的方式来接收的,那么接收的就是 临时对象的 引用,一位临时对象具有常性,所以,普通的引用去引用临时对象,发生了 权限的放大,就会报错;所以我们上述加了 const 的引用去引用 这个 临时对象才没有报错。

在支持 列表初始化之后,不止可以对结构体来初始化,我们一般使用 int 等等的内置类型都可以用 列表来初始化了,而且可以不写 = 符号

	// 下面三种int 变量的初始化结果是一样的
	int a = 1;
	int b = {1};
	int c {1};

	// 下述两种数组的初始化方式是一样的
	int arr[] = { 1,2,3 };
	int arr[] { 1,2,3 };

支持内置类型数组,使用 new 的时候,使用 列表初始化:

	int* prt1 = new int[3]{ 1, 2, 3 };

同样支持 自定义类型数组,使用 new 时,使用 列表初始化:
 

    point p1 = { 0, 0 };
	point p2{0, 0};

    point* ptr2 = new point[2]{ {1,2}, {2,3} };
	point* ptr2 = new point[2]{ point(1,2),point(2,3)};
	point* ptr2 = new point[2]{ p1, p2 };

当然,上述使用 列表初始化的方式,本质上是调用 构造函数吗,如果不想别人使用这样的方式来初始化的对象的话,可以在构造函数之前加一个 explicit 修饰词来修饰构造函数

	explicit point(int x, int y)
		:_x(x)
		, _y(y)
	{}

加上这个修饰词之后,下述的初始化方式就不支持了:
 

 std::initializer_list

cplusplus.com/reference/initializer_list/initializer_list/

 先来看下述的两行代码,使用的语法是否是一样的:
 

	vector<int> v1 = { 1,2 };
	point p = { 1,2 };

首先明确,这两行代码是使用不同的规则来实现的。

point 对象是使用上述的 列表初始化来实现的,调用的是构造函数;可能还有人认为vector 对象也是使用 列表初始化的方式来实现的,但是上述还可以这样写:
 

	vector<int> v1 = { 1,2 ,3,4,5,5,6};

这种方式放在没有这么多参数的 point()当中就不行了:

实际上,是 C++ 当中创建一个新的容器叫做 initializer_list :

 只要是用 "{}" 括起来,都可以识别成 initializer_list

 他还有迭代器的实现,其实是一个 常量数组。这个常量数组是存储在 常量区的。

 其实 initializer_list 的实现就是两个指针,指向 常量数组的起始位置和 终止位置:
 

	auto il1 = { 10, 20, 30 };
	initializer_list<int> il2 = { 10, 20, 30 };
	cout << typeid(il1).name() << endl;
	cout << sizeof(il1) << endl;

输出;

class std::initializer_list<int>
16

    initializer_list<int> il2 = { 10, 20, 30 }; 这句代码的本质是调用 initializer_list 的构造函数,想办法取到 { 10, 20, 30 } 这段空间的 起始地址和 结束地址。


我们现在反观 vector 是如何实现 ,    vector<int> v1 = { 1,2 ,3,4,5,5,6}; 这样的方式来构造对象的。

其实 是 vector 当中专门写了 一个 支持传入  initializer_list 作为参数,来构造 vector 的构造函数:

 所以,至此就知道了为什么 vector 支持 {1,2,3,4,5}这样的方式去构造 vector 的 对象,而 point 不行。

其实,在C++ 11 之后,就不止vector 容器支持 initializer_list 作为参数的方式来进行构造对象,而是基本都支持了 initializer_list 作为参数的构造函数。

比如 map :

   map<string, string> dict = { {"sort", "排序"}, {"left", "左边"} };

 这里的 { {"sort", "排序"}, {"left", "左边"} }; 会被识别为一个  initializer_list<pair> 。其中 {"sort", "排序"} 和 {"left", "左边"},是 一个 pair 对象,当然这里使用的是 列表初始化的方式,我们还可以使用 有名对象,和匿名对象的方式来使用。

在 vector 的模拟实现当中加上 initializer_list 作为参数的构造函数

  其实实现也很简单,因为 initializer_list 是支持迭代器的,所以,我们可以直接先把 vector 开和 initializer_list  一样大的空间,然后使用范围for 来一一赋值就行:

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

声明

 C++ 的类型书写比较麻烦,声明也麻烦,特别是在加上模版之后。C++11 之后,简化了很多的声明方式。

aotu  

 在C++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部的变量默认就是自动存储类型,所以auto就没什么价值了。C++11中废弃auto原来的用法,将其用于实现自动类型腿断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初始化值的类型。

 aotu在范围for,和一些复杂的模版上经常使用;但是,如果是类型比较复杂的模版参数,使用 aotu的话当然语法是通过的,但是写上aotu之后,其他人,或者是以后自己再看这部分代码的时候可读性的就变得很差,不知道此处的 aotu 是什么类型的。所以在书写复杂模版参数的时候要把这点考虑进去。

int i = 10;
auto p = &i;
auto pf = malloc;

cout << typeid(p).name() << endl;
cout << typeid(pf).name() << endl;

输出:

 如上述例子,关于 C 当中非常难写的函数指针他也可以推导出来。

 还有需要注意的是,使用 aotu 的话,必须显示的初始化,不能像下述一样书写:
 

auto x;

想想也知道,此时编译器不知道 x 是什么类型变量。

decltype 

 当我们像定义之前我们定义过的某个变量的同类型的变量,那么除了使用 aotu 之外,我们还可以使用什么来定义呢?

使用 typeid 是不行的,因为 typeid 取出来的是 类型的字符串:

	auto ptr = malloc;
	cout << typeid(ptr).name() << endl;

    // 不行,编译器报错
	typeid(ptr).name() ptr2;

在C++ 11 当中新推出了 decltype ,它可以推导出类型,然后使用这个类型进行初始化变量:

	auto ptr = malloc;
	cout << typeid(ptr).name() << endl;
	
	decltype(ptr) ptr2;
    decltype(malloc) ptr3;

 而且,aotu 的话,必须显示初始化;但是使用 decltype 的话可以只是单纯定义一个变量出来。如上述代码所示。

它还可以作为模版的实参传入:
 

	auto ptr = malloc;
	
	vector<decltype(ptr)> v;

还可以是一个 表达式的结果的类型推导:

int x = 1;
double y = 2;

decltype(x * y) ret;

nullptr

在 c++11 当中为了弥补 C 当中的一个坑,所增加的一个 空指针。在C 当中的是这样的定义 NULL的:
 

#define NULL 0

发现,NULL 直接就替换成 0 了,不是指针类型,这是不对的,所以在C++ 11 对此进行修改:

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

 ((void *)0)  指针类型,把 0 强转为 指针类型。

void func(int x)
{}

void func(int* p)
{}

int main()
{
	int* p = NULL; // int* p = 0;
	func(NULL); // func(0);

	return 0;
}

如上所示,主函数的那种实际匹配的是 第一个func 函数,而不是 第二个。

其实上述 NULL 的坑,宏占了一大部分,我们在书写代码的过程当中尽量要用 const ,enum ,inline 取替代宏。

 C++11 之后 STL 的一些变化

新容器 

 用橘色圈起来是C++11中的一些几个新容器。关于 unordered_map 和 unordered_set 的介绍和模拟实现请看 下述博客:
C++ - unordered系列关联式容器介绍 - 和 set map 的比较-CSDN博客

C++ - 封装 unordered_set 和 unordered_map - 哈希桶的迭代器实现_chihiro1122的博客-CSDN博客

C++ - 模版进阶 - array_chihiro1122的博客-CSDN博客
 

 我们来简单介绍一下 forward_list,这个容器 和 array 容器一样鸡肋。

array 容器 只是相比于 C 当中的数组,在调用 operator[]() 函数时候,比如C 的 数组多了一些越界检查,但是,想要检查用 vector  不好吗?此处的 array  是静态的数组,他的本意是想要替换 C 当中的数组,但是 C++ 当中有了 vector 容器 ,array 容器就不好用了。

 forward_list的本质也是一个单链表,使用的是单向迭代器。

这个容器鸡肋就鸡肋在,只支持 头插头删;尾差尾删不支持。因为单链表的尾删效率很低,因为删除最后一个要找到前一个;而且其中的 insert()和 erase()函数也是在指定位置之后插入/删除。在指定位置之前插入/删除,也是要找到上一个,效率也不高。

 容器中的一些新方法

如果我们再细细去看会发现基本每个容器中都增加了一些C++11的方法,但是其实很多都是用得比较少的。
比如提供了cbegin和cend方法返回const迭代器等等,但是实际意义不大,因为begin和end也是可以返回const迭代器的,这些都是属于锦上添花的操作。

 正常我们使用 const 版本的begin()和 end()就行了,上述的用处不大。

新增的方法接口,就是我们上述提到过的  支持 initializer_list  做参数的 构造函数。这个构造函数很多 容器都支持了。

不止上述的更新实际上C++11更新后,容器中增加的新方法最后用的插入接口函数的右值引用版本:

cplusplus.com/reference/vector/vector/emplace_back/

www.cplusplus.com/reference/vector/vector/push_back/

cplusplus.com/reference/map/map/insert/

cplusplus.com/reference/map/map/emplace/

这些接口的实现,提升了效率,使用的就是 右值引用和移动语义 ,具体我们在下述进行说明。其中的 emplace还涉及模板的可变参数。

而且,不是上述新增的接口,其中的 push_back ()也进行的了升级,上述的带来的性能提升是在 调用 emplace 的情况下,在 push_back()升级之后,我们调用 push_back ()也可以有性能提升。而且,在有些地方的提升还非常大。具体看下述对  右值引用和移动语义 的介绍。

在C++11 之后,所有的容器都提供了 移动构造 和 移动赋值的版本,可以到达在有些情况下,深拷贝的性能提升了 约 90%。

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

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

相关文章

15046-2011 脂肪酰二乙醇胺 学习笔记

声明 本文是学习GB-T 15046-2011 脂肪酰二乙醇胺.pdf而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了脂肪酰二乙醇胺的产品分类、要求、试验方法、检验规则和标志、包装、运输、贮存和保 质期。 本标准适用于由脂肪酸甲酯或脂肪…

C++(反向迭代器)

前言&#xff1a; 上一章我们介绍了适配器&#xff0c;也提了一下迭代器适配器&#xff0c;今天我们就从反向迭代器把迭代器适配器给解释一下。 既然 都叫迭代器容器了 就说名只要接口合适他可以封装实现各种容器需求包括vector list 。 目录 1.反向迭代器设计 1.1反向迭代…

浅谈电气防火限流式保护器在小型人员密集场所中的应用

摘要&#xff1a;本文通过结合城市中小型人员密集场所的特点和电气防火限流式保护器的功能&#xff0c;阐述了该类筑物预防电气火灾事故的方法。 关键词&#xff1a;小型人员密集场所&#xff1b;电气防火限流式保护器 0&#xff1a;概述 近年来&#xff0c;随着社会经济的不…

C++标准模板(STL)- 类型支持 (定宽整数类型)(INT8_C,INTMAX_C,UINT8_C,UINTMAX_C,格式化宏常量)

最小宽度整数常量的函数宏 INT8_CINT16_CINT32_CINT64_C 展开成拥有其实参所指定的值且类型分别为 int_least8_t、int_least16_t、int_least32_t、int_least64_t 的整数常量表达式 (宏函数) INTMAX_C 展开成拥有其实参所指定的值且类型为 intmax_t 的整数常量表达式 (宏函数) U…

pytorch算力与有效性分析

pytorch Windows中安装深度学习环境参考文档机器环境说明3080机器 Windows11qt_env 满足遥感CS软件分割、目标检测、变化检测的需要gtrs 主要是为了满足遥感监测管理平台&#xff08;BS&#xff09;系统使用的&#xff0c;无深度学习环境内容swin_env 与 qt_env 基本一致od 用于…

力扣第100题 相同的数 c++ 二叉 简单易懂+注释

题目 100. 相同的树 简单 给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 示例 1&#xff1a; 输入&#xff1a;p [1,2,3], q [1,2,3] 输出…

代码随想录算法训练营第五十九天 | 动态规划 part 17 | 647. 回文子串、516.最长回文子序列

目录 647. 回文子串思路思路2 双指针代码 516.最长回文子序列思路代码 647. 回文子串 Leetcode 思路 dp[i][j]&#xff1a;表示区间范围[i,j] &#xff08;注意是左闭右闭&#xff09;的子串是否是回文子串&#xff0c;如果是dp[i][j]为true&#xff0c;否则为false。递推公式…

python和go相互调用的两种方法

前言 Python 和 Go 语言是两种不同的编程语言&#xff0c;它们分别有自己的优势和适用场景。在一些项目中&#xff0c;由于团队内已有的技术栈或者某一部分业务的需求&#xff0c;可能需要 Python 和 Go 相互调用,以此来提升效率和性能。 性能优势 Go 通常比 Python 更高效&…

什么是DOM(Document Object Model)?如何使用JavaScript操作DOM元素?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 什么是DOM&#xff1f;⭐ 如何使用JavaScript操作DOM元素&#xff1f;1. 获取DOM元素2. 修改元素内容3. 修改元素属性4. 添加和移除元素5. 添加和移除事件监听器 ⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界…

【开发篇】十七、消息:模拟订单短信通知

文章目录 1、消息2、JMS3、AMQP4、案例&#xff1a;模拟订单短信通知 相关文章&#xff1a; 【同步通讯与异步通讯】 1、消息 消息的发送方&#xff0c;即生产者。消息的接收方&#xff0c;即消费者。同步通信就行打视频&#xff0c;等着对方接电话才能继续往下&#xff0c;而…

JDBC 【SQL注入】

一、SQL注入&#x1f353; (一)、SQL注入问题&#x1f95d; 1.向jdbc_user表中 插入两条数据 # 插入2条数据 INSERT INTO jdbc_user VALUES(NULL,jack,123456,2020/2/24); INSERT INTO jdbc_user VALUES(NULL,tom,123456,2020/2/24);2.SQL注入演示 # SQL注入演示 -- 填写…

泊车功能专题介绍 ———— AVP系统基础数据交互内容

文章目录 系统架构系统功能描述云端子系统车辆子系统场端子系统用户APP 工作流程基础数据交互内容AVP 系统基础数据交互服务车/用户 - 云基础数据交互内容车位查询工作流程技术要求数据交互要求 车位预约工作流程技术要求数据交互要求 取消预约工作流程技术要求数据交互要求 泊…

利用C++开发一个迷你的英文单词录入和测试小程序-升级版本

我们现在有了一个本地sqlite3的迷你英文单词小测试工具&#xff0c;需求就跟工作当中一样是不断变更的。这里虚构两个场景&#xff0c;并且一步一步的完成最终升级后的小demo。 场景&#xff1a;数据不依赖本地sqlite3&#xff0c;需要支持远程访问&#xff0c;用目前的restfu…

深入探究C++编程中的资源泄漏问题

目录 1、GDI对象泄漏 1.1、何为GDI资源泄漏&#xff1f; 1.2、使用GDIView工具排查GDI对象泄漏 1.3、有时可能需要结合其他方法去排查 1.4、如何保证没有GDI对象泄漏&#xff1f; 2、进程句柄泄漏 2.1、何为进程句柄泄漏&#xff1f; 2.2、创建线程时的线程句柄泄漏 …

Dijkstra 邻接表表示算法 | 贪心算法实现--附C++/JAVA实现源码

以下是详细步骤。 创建大小为 V 的最小堆,其中 V 是给定图中的顶点数。最小堆的每个节点包含顶点编号和顶点的距离值。 以源顶点为根初始化最小堆(分配给源顶点的距离值为0)。分配给所有其他顶点的距离值为 INF(无限)。 当最小堆不为空时,执行以下操作: 从最小堆中提取…

JVM技术文档--JVM诊断调优工具Arthas--阿里巴巴开源工具--一文搞懂Arthas--快速上手--国庆开卷!!

​ Arthas首页 简介 | arthas Arthas官网文档 Arthas首页、文档和下载 - 开源 Java 诊断工具 - OSCHINA - 中文开源技术交流社区 阿丹&#xff1a; 之前聊过了一些关于JMV中的分区等等&#xff0c;但是有同学还是在后台问我&#xff0c;还有私信问我&#xff0c;学了这些…

人工智能驱动的古彝文识别:保护和传承古彝文文化

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

从零开始 Spring Cloud 13:分布式事务

从零开始 Spring Cloud 13&#xff1a;分布式事务 1.分布式事务问题 用一个示例项目演示在分布式系统中使用事务会产生的问题。 示例项目的 SQL&#xff1a;seata_demo.sql 示例项目代码&#xff1a;seata-demo.zip 这个示例项目中的微服务的互相调用依赖于 Nacos&#xf…

低代码平台如何借助Nginx实现网关服务

摘要&#xff1a;本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 前言 在典型的系统部署架构中&#xff0c;应用服务器是一种软件或硬件系统&#xff0c…

解决Ubuntu18.04安装好搜狗输入法后无法打出中文的问题

首先下载安装 搜狗拼音输入法 &#xff0c;下载选择&#xff1a; x86_64 在ubuntu中设置 fcitx 最后发现安装好了&#xff0c;图标有了 &#xff0c;但是使用时不能输入中文&#xff0c;使用下面的命令解决&#xff1a; sudo apt install libqt5qml5 libqt5quick5 libqt5qu…