| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> C++11常用新特性(一) -> 正文阅读 |
|
[C++知识库]C++11常用新特性(一) |
最近工作中,遇到一些问题,使用 C++11 实现起来会更加方便,而线上的生产环境还不支持 C++11,于是决定新年开工后,在组内把 C++11 推广开来,整理以下文档,方便自己查阅,也方便同事快速上手。(对于异步编程十分实用的 Future/Promise 以及智能指针等,将不做整理介绍,组内使用的框架已经支持并广泛使用了,用的是自己公司参考 boost 实现的版本) 最近学习人工智能的时候,发现了一个很好的学习网站,分享给大家,点击查看 nullptrnullptr 出现的目的是为了替代 NULL。 在某种意义上来说,传统 C++ 会把 NULL、0 视为同一种东西,这取决于编译器如何定义 NULL,有些编译器会将 NULL 定义为 ((void*)0),有些则会直接将其定义为 0。 C++ 不允许直接将 void 隐式转换到其他类型,但如果 NULL 被定义为 ((void)0),那么当编译char *ch = NULL;时,NULL 只好被定义为 0。 而这依然会产生问题,将导致了 C++ 中重载特性会发生混乱,考虑:
对于这两个函数来说,如果 NULL 又被定义为了 0 那么 foo(NULL); 这个语句将会去调用 foo(int),从而导致代码违反直观。 为了解决这个问题,C++11 引入了 nullptr 关键字,专门用来区分空指针、0。 nullptr 的类型为 nullptr_t,能够隐式的转换为任何指针或成员指针的类型,也能和他们进行相等或者不等的比较。 当需要使用 NULL 时候,养成直接使用 nullptr的习惯。 类型推导C++11 引入了 auto 和 decltype 这两个关键字实现了类型推导,让编译器来操心变量的类型。 auto auto 在很早以前就已经进入了 C++,但是他始终作为一个存储类型的指示符存在,与 register 并存。在传统 C++ 中,如果一个变量没有声明为 register 变量,将自动被视为一个 auto 变量。而随着 register 被弃用,对 auto 的语义变更也就非常自然了。 使用 auto 进行类型推导的一个最为常见而且显著的例子就是迭代器。在以前我们需要这样来书写一个迭代器:
而有了 auto 之后可以:
一些其他的常见用法:
注意:auto 不能用于函数传参,因此下面的做法是无法通过编译的(考虑重载的问题,我们应该使用模板):
此外,auto 还不能用于推导数组类型:
decltype decltype 关键字是为了解决 auto 关键字只能对变量进行类型推导的缺陷而出现的。它的用法和 sizeof 很相似:
在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。 有时候,我们可能需要计算某个表达式的类型,例如:
拖尾返回类型、auto 与 decltype 配合 你可能会思考,auto 能不能用于推导函数的返回类型。考虑这样一个例子加法函数的例子,在传统 C++ 中我们必须这么写:
这样的代码其实变得很丑陋,因为程序员在使用这个模板函数的时候,必须明确指出返回类型。但事实上我们并不知道 add() 这个函数会做什么样的操作,获得一个什么样的返回类型。 在 C++11 中这个问题得到解决。虽然你可能马上回反应出来使用 decltype 推导 x+y 的类型,写出这样的代码:
但事实上这样的写法并不能通过编译。这是因为在编译器读到 decltype(x+y) 时,x 和 y 尚未被定义。为了解决这个问题,C++11 还引入了一个叫做拖尾返回类型(trailing return type),利用 auto 关键字将返回类型后置:
从 C++14 开始是可以直接让普通函数具备返回值推导,因此下面的写法变得合法:
区间迭代基于范围的 for 循环 C++11 引入了基于范围的迭代写法,我们拥有了能够写出像 Python 一样简洁的循环语句。 最常用的 std::vector 遍历将从原来的样子:
变得非常的简单:
初始化列表 C++11 提供了统一的语法来初始化任意的对象,例如:
C++11 还把初始化列表的概念绑定到了类型上,并将其称之为std::initializer_list,允许构造函数或其他函数像参数一样使用初始化列表,这就为类对象的初始化与普通数组和 POD 的初始化方法提供了统一的桥梁,例如:
模板增强外部模板 传统 C++ 中,模板只有在使用时才会被编译器实例化。只要在每个编译单元(文件)中编译的代码中遇到了被完整定义的模板,都会实例化。这就产生了重复实例化而导致的编译时间的增加。并且,我们没有办法通知编译器不要触发模板实例化。 C++11 引入了外部模板,扩充了原来的强制编译器在特定位置实例化模板的语法,使得能够显式的告诉编译器何时进行模板的实例化:
尖括号 “>” 在传统 C++ 的编译器中,>>一律被当做右移运算符来进行处理。但实际上我们很容易就写出了嵌套模板的代码:
这在传统C编译器下是不能够被编译的,而 C11 开始,连续的右尖括号将变得合法,并且能够顺利通过编译。 类型别名模板 在传统 C++中,typedef 可以为类型定义一个新的名称,但是却没有办法为模板定义一个新的名称。因为,模板不是类型。例如:
C++11 使用 using 引入了下面这种形式的写法,并且同时支持对传统 typedef 相同的功效:
默认模板参数 我们可能定义了一个加法函数:
但在使用时发现,要使用 add,就必须每次都指定其模板参数的类型。 在 C++11 中提供了一种便利,可以指定模板的默认参数:
构造函数委托构造 C++11 引入了委托构造的概念,这使得构造函数可以在同一个类中一个构造函数调用另一个构造函数,从而达到简化代码的目的:
继承构造 在继承体系中,如果派生类想要使用基类的构造函数,需要在构造函数中显式声明。 假若基类拥有为数众多的不同版本的构造函数,这样,在派生类中得写很多对应的“透传”构造函数。如下:
C++11的继承构造:
如果一个继承构造函数不被相关的代码使用,编译器不会为之产生真正的函数代码,这样比透传基类各种构造函数更加节省目标代码空间。 新增容器std::array std::array 保存在栈内存中,相比堆内存中的 std::vector,我们能够灵活的访问这里面的元素,从而获得更高的性能。 std::array 会在编译时创建一个固定大小的数组,std::array 不能够被隐式的转换成指针,使用 std::array只需指定其类型和大小即可:
当我们开始用上了 std::array 时,难免会遇到要将其兼容 C 风格的接口,这里有三种做法:
std::forward_list std::forward_list 是一个列表容器,使用方法和 std::list 基本类似。 和 std::list 的双向链表的实现不同,std::forward_list 使用单向链表进行实现,提供了 O(1) 复杂度的元素插入,不支持快速随机访问(这也是链表的特点),也是标准库容器中唯一一个不提供 size() 方法的容器。当不需要双向迭代时,具有比 std::list 更高的空间利用率。 无序容器 C++11 引入了两组无序容器: std::unordered_map/std::unordered_multimap和 std::unordered_set/std::unordered_multiset。 无序容器中的元素是不进行排序的,内部通过 Hash 表实现,插入和搜索元素的平均复杂度为 O(constant)。 元组 std::tuple 元组的使用有三个核心的函数: std::make_tuple: 构造元组 std::get: 获得元组某个位置的值 std::tie: 元组拆包
合并两个元组,可以通过 std::tuple_cat 来实现。
正则表达式正则表达式描述了一种字符串匹配的模式。一般使用正则表达式主要是实现下面三个需求:
C++11 提供的正则表达式库操作 std::string 对象,对模式 std::regex (本质是 std::basic_regex)进行初始化,通过 std::regex_match 进行匹配,从而产生 std::smatch (本质是 std::match_results 对象)。 我们通过一个简单的例子来简单介绍这个库的使用。考虑下面的正则表达式: [a-z]+.txt: 在这个正则表达式中, [a-z] 表示匹配一个小写字母, + 可以使前面的表达式匹配多次,因此 [a-z]+ 能够匹配一个及以上小写字母组成的字符串。在正则表达式中一个 . 表示匹配任意字符,而 . 转义后则表示匹配字符 . ,最后的 txt 表示严格匹配 txt 这三个字母。因此这个正则表达式的所要匹配的内容就是文件名为纯小写字母的文本文件。 std::regex_match 用于匹配字符串和正则表达式,有很多不同的重载形式。最简单的一个形式就是传入std::string 以及一个 std::regex 进行匹配,当匹配成功时,会返回 true,否则返回 false。例如:
另一种常用的形式就是依次传入 std::string/std::smatch/std::regex 三个参数,其中 std::smatch 的本质其实是 std::match_results,在标准库中, std::smatch 被定义为了 std::match_results,也就是一个子串迭代器类型的 match_results。使用 std::smatch 可以方便的对匹配的结果进行获取,例如:
以上两个代码段的输出结果为:
|
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 16:52:48- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |