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

目录

C++的发展史了解

 统一列表初始化

 {}初始化

 std::initializer_list

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

声明

aotu  

decltype 

nullptr

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

新容器 

 容器中的一些新方法


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.rhkb.cn/news/151896.html

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

相关文章

基于SSM的实验室考勤管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

CCF CSP认证 历年题目自练Day25

题目 试题编号&#xff1a; 201403-3 试题名称&#xff1a; 命令行选项 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 256.0MB 问题描述&#xff1a; 问题描述   请你写一个命令行分析程序,用以分析给定的命令行里包含哪些选项。每个命令行由若干个字符串组成,它们之间…

插入排序/折半插入排序

插入排序/折半插入排序 插入排序 插入排序(英语&#xff1a;Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。插入排序在实现上&#xff0c;通常…

光伏储能直流系统MATLAB仿真(PV光伏阵列+Boost DCDC变换器+负载+双向DCDC变换器+锂离子电池系统)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

前端 | AjaxAxios模块

文章目录 1. Ajax1.1 Ajax介绍1.2 Ajax作用1.3 同步异步1.4 原生Ajax 2. Axios2.1 Axios下载2.2 Axios基本使用2.3 Axios方法 1. Ajax 1.1 Ajax介绍 Ajax: 全称&#xff08;Asynchronous JavaScript And XML&#xff09;&#xff0c;异步的JavaScript和XML。 1.2 Ajax作用 …

javaee SpringMVC中json的使用

jsp <%--Created by IntelliJ IDEA.User: 呆萌老师:QQ:2398779723Date: 2019/12/6Time: 15:55To change this template use File | Settings | File Templates. --%> <% page contentType"text/html;charsetUTF-8" language"java" %> <%St…

蓝桥杯每日一题2023.10.7

跑步锻炼 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 简单枚举&#xff0c;对于2的情况特判即可 #include<bits/stdc.h> using namespace std; int num, ans, flag; int m[13] {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; bool is_ren(int n) {if((n %…

《C++ Primer》第5章 语句

参考资料&#xff1a; 《C Primer》第5版《C Primer 习题集》第5版 5.1 简单语句&#xff08;P154&#xff09; 在一个表达式的末尾加上 ; 就构成了表达式语句&#xff0c;其作用是执行表达式并丢弃结果。 空语句 由单独的 ; 构成的语句为空语句。空语句常用于语法上需要一…

【网络】路由器和交换机的区别

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的帮助&#x1…

6.MySql连接SqlYog

MySql连接SqlYog SqlYog和navicat均是数据可视化工具&#xff0c;熟悉其一即可 SqlYog下载安装 连接&#xff0c;密码和端口号一定要正确&#xff01;&#xff01;&#xff01; 2.保存到数据库 创建数据库&表 创建数据库 创建成功 创建表 点击保存 查看表数据的…

jira 浏览器插件在问题列表页快速编辑问题标题

jira-issueTable-quicker 这是一个可以帮助我们在问题表格页快速编辑问题的浏览器插件 github 地址 功能介绍 jira 不可否认是一个可以帮助有效提高工作效率的工具&#xff0c;但是我们在使用 jira 时使用问题表格可以让我们看到跟多的内容而不用关注细节&#xff0c;但是目…

vulnhub靶场 Kioptrix-level-1

简介&#xff1a; vulnhub是一个提供靶场环境的平台。而Kioptrix-level-1就是一个对新手比较友好的靶场。初学渗透的同学可以做做试试看&#xff0c;项目地址如下。 项目地址&#xff1a;Kioptrix: Level 1 (#1) ~ VulnHub 信息收集 查看本机IP&#xff0c;靶机跟kali都是使用…

常用的分布式ID解决方案原理解析

目录 前言 一&#xff1a;分布式ID的使用场景 二&#xff1a;分布式ID设计的技术指标 三&#xff1a;常见的分布式ID生成策略 3.1 UUID 3.2 数据库生成 3.3 数据库的多主模式 3.4 号段模式 3.5 雪花算法 前言 分布式ID的生成是分布式系统中非常核心的基础性模块&#…

4.方法操作实例变量 对象的行为

4.1 操作对象状态的方法 同一类型的每个对象能够有不同的方法行为&#xff0c;任一类的每个实例都带有相同的方法&#xff0c;但是方法可以根据实例变量的值来表现不同的行为。 play()会播放title值表示的歌曲&#xff0c;调用某个实例的play()可能会播放“Politik”而另一个会…

【重拾C语言】七、指针(一)指针与变量、指针操作、指向指针的指针

目录 前言 七、指针 7.1 指针与变量 7.1.1 指针类型和指针变量 7.1.2 指针所指变量 7.1.3 空指针、无效指针 7.2 指针操作 7.2.1 指针的算术运算 7.2.2 指针的比较 7.2.3 指针的递增和递减 7.3 指向指针的指针 前言 指针是C语言中一个重要的概念正确灵活运用指针 可…

Android原生实现控件圆角方案(API28及以上)

Android控件的圆角效果的实现方式有很多种&#xff0c;这里介绍一下另一种Android原生的圆角实现方案&#xff08;API28及以上&#xff09;。 我们利用ShapeAppearanceModel、MaterialShapeDrawable来实现一个圆角/切角的Button。 实现效果如下图 我们在为控件添加阴影的基础上…

波奇学C++:用红黑树模拟实现map和set

用同一个树的类模板封装map(key/value)和set(key) 红黑树的Node template<class T> struct RBTreeNode {RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;T _data;Colour _col;RBTreeNode(const T& data):_left(nullptr),_r…

kafka日志文件详解及生产常见问题总结

一、kafka的log日志梳理 日志文件是kafka根目录下的config/server.properties文件&#xff0c;配置log.dirs/usr/local/kafka/kafka-logs&#xff0c;kafka一部分数据包含当前Broker节点的消息数据(在Kafka中称为Log日志)&#xff0c;称为无状态数据&#xff0c;另外一部分存在…

选择适合建筑公司的企业网盘平台

随着城市化进程的加速&#xff0c;越来越多的人开始关注乡村生活品质。Z公司以其标准化产品和优质资源整合&#xff0c;为回乡建房人群提供了一种全新的、高品质的整体解决方案。 Z公司深入调研了10W的回乡建房人群需求&#xff0c;组建了设计、工艺、供应链方面的专家团队&…

【Gradle-10】不可忽视的构建分析

1、前言 构建性能对于生产力至关重要。 随着项目越来越复杂&#xff0c;花费在构建上的时间就越长&#xff0c;开发效率就越低。 通过分析构建过程&#xff0c;可以了解项目构建的时间都花在哪&#xff0c;以及项目存在哪些潜在的问题&#xff0c;找到构建瓶颈&#xff0c;解…