高速上手 C++11/14/17
欧长坤 (hi@changkun.us)
最后更新 2019 年 1 月 31 日- v1.0.1-97-g4a8837e
版权声明
本书系欧长坤著,采用“知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 (cc by-nc-sa)”进行许
可。http://creativecommons.org/licenses/by-nc-nd/4.0/
1
目录
序言
目录
目录
引言 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
目标读者 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
本书目的 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
相关代码 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
第 1 章迈向 C++11/14/17
1.1 被弃用的特性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 与 C 的兼容性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
7
7
7
8
8
8
9
进一步阅读的参考文献 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
第 2 章语言可用性的强化
11
2.1 常量 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
nullptr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
constexpr
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2 变量及其初始化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
if/switch 变量声明强化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
初始化列表 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
结构化绑定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.3 类型推导 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
auto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
decltype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
尾返回类型推导 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
decltype(auto)
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.4 控制流 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
if constexpr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
区间 for 迭代 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.5 模板 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
外部模板 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2
目录
目录
尖括号 “>” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
类型别名模板 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
默认模板参数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
变长参数模板 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
折叠表达式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.6 面向对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
委托构造 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
继承构造 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
显式虚函数重载 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
显式禁用默认函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
强类型枚举 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
总结 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
习题 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
进一步阅读的参考文献 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
第 3 章语言运行期的强化
32
3.1 Lambda 表达式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Lambda 表达式基础 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
泛型 Lambda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.2 函数对象包装器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
std::function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
std::bind/std::placeholder
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.3 右值引用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
左值、右值的纯右值、将亡值、右值 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
右值引用和左值引用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
移动语义 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
完美转发 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
总结 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
第 4 章标准库:容器
42
3
目录
目录
4.1 std::array 和 std::forward_list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
std::array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
std::forward_list
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.2 无序容器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.3 元组 std::tuple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
元组基本操作 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
运行期索引 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
元组合并与遍历 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
总结 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
第 5 章标准库:指针
48
5.1 RAII 与引用计数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.2 std::shared_ptr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.3 std::unique_ptr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.4 std::weak_ptr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
总结 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
进一步阅读的参考资料 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
第 6 章标准库:正则表达式
53
6.1 正则表达式简介 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
普通字符 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
特殊字符 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
限定符 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.2 std::regex 及其相关 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
总结 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
进一步阅读的参考资料 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
第 7 章标准库:线程与并发
56
7.1 std::thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
7.2 std::mutex, std::unique_lock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
7.3 std::future, std::packaged_task . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
4
目录
目录
7.4 std::condition_variable
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
总结 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
进一步阅读的参考资料 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
第 8 章标准库:文件系统
60
8.1 文档与链接 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
8.2 std::filesystem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
第 9 章其他杂项
61
9.1 新类型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
long long int . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
9.2 noexcept 的修饰和操作 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
9.3 字面量 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
原始字符串字面量 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
自定义字面量 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
总结 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
第 10 章展望:C++20 简介
64
10.1 主要入选特性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
非类型模板参数的 auto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
std::variant<> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
10.2 未入选特性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Concepts TS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
总结 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
进一步阅读的参考资料 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
附录 1:进一步阅读的学习材料
附录 2:现代 C++ 的最佳实践
67
67
常用工具 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
代码风格 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
整体性能 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
5
目录
目录
代码安全 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
可维护性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
可移植性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
6
序言
序言
引言
C++ 是一个用户群体相当大的语言。从 C++98 的出现到 C++11 的正式定稿经历了长达〸年多之
久的积累。C++14/17 则是作为对 C++11 的重要补充和优化,所有这些新标准中扩充的特性,给 C++
这门语言注入了新的活力。那些还在坚持使用传统 C++(本书把 C++98 及其之前的 C++ 特性均称
之为传统 C++)而未接触过 C++11/14/17 的 C++ 程序员在见到诸如 Lambda 表达式这类全新特性
时,甚至会流露出『学的不是同一门语言』的惊叹之情。
C++1x (或现代 C++,本书中均指 C++11/14/17) 为传统 C++ 注入的大量特性使得整个 C++
变得更加像一门现代化的语言。C++1x 不仅仅增强了 C++ 语言自身的可用性,auto 关键字语义的修
改使得我们更加有信心来操控极度复杂的模板类型。同时还对语言运行期进行了大量的强化,Lambda
表达式的出现让 C++ 具有了『匿名函数』的『闭包』特性,而这一特性几乎在现代的编程语言(诸如
Python/Swift/. . . )中已经司空见惯,右值引用的出现解决了 C++ 长期以来被人诟病的临时对象效率
问题等等。
C++17 则是近三年依赖 C++ 社区一致推进的方向,也指出了现代 C++ 编程的一个重要发展方
向。尽管它的出现并不如 C++11 的分量之重,但它包含了大量小而美的语言与特性(例如结构化绑定),
这些特性的出现再一次修正了我们在 C++ 中的编程范式。
现代 C++ 还为自身的标准库增加了非常多的工具和方法,诸如在语言自身标准的层面上制定了 std
::thread,从而支持了并发编程,在不同平台上不再依赖于系统底层的 API,实现了语言层面的跨平台
支持;std::regex 提供了完整的正则表达式支持等等。C++98 已经被实践证明了是一种非常成功的『范
型』,而 C++1x 的出现,则进一步推动这种范型,让 C++ 成为系统程序设计和库开发更好的语言。
总而言之,我们作为 C++ 的拥护与实践者,始终保持接纳新事物的开放心态,才能更快的推进 C++
的发展,使得这门古老而又新颖的语言更加充满活力。
目标读者
1. 本书假定读者已经熟悉了传统 C++ ,至少在阅读传统 C++ 代码上不具备任何困难。换句话说,
那些长期使用传统 C++ 进行编码的人、渴望在短时间内迅速了解现代 C++ 特性的人非常适合
阅读本书;
2. 本书一定程度上介绍了一些现代 C++ 的黑魔法,但这些魔法毕竟有限,不适合希望进阶学习现代
C++ 的读者,本书的定位系现代 C++ 的快速上手。当然,希望进阶学习的读者可以使用本书来
回顾并检验自己对 现代 C++ 的熟悉度。
本书目的
本书号称『高速上手』,从内容上对二〸一世纪二〸年代之前产生 C++ 的相关特性做了非常相对全
面的介绍,读者可以自行根据下面的目录选取感兴趣的内容进行学习,快速熟悉需要了解的内容。这些
特性并不需要全部掌握,只需针对自己的使用需求和特定的应用场景,学习、查阅最适合自己的新特性
7
相关代码
即可。
第 1 章迈向 C++11/14/17
同时,本书在介绍这些特性的过程中,尽可能简单明了的介绍了这些特性产生的历史背景和技术需
求,这为理解这些特性、运用这些特性提供了很大的帮助。
此外,笔者希望读者在阅读本书后,能够努力在新项目中直接使用 C++17,并努力将旧项目逐步迁
移到 C++17。也算是笔者为推进现代 C++ 的普及贡献了一些绵薄之力。
相关代码
本书每章中都出现了大量的代码,如果你在跟随本书介绍特性的思路编写自己的代码遇到问题时,不
妨读一读随书附上的源码,你可以在这里中找到书中介绍过的全部的源码,所有代码按章节组织,文件
夹名称为章节序号。
第 1 章迈向 C++11/14/17
编译环境:本书将使用 clang++ 作为唯一使用的编译器,同时总是在代码中使用 -std=c++17 编译标
志。
clang ++ -v
Apple LLVM version 9.1.0 (clang -902.0.39.1)
Target : x86_64 -apple - darwin17 .5.0
Thread model : posix
InstalledDir : / Library / Developer / CommandLineTools /usr/bin
1
2
3
4
5
1.1 被弃用的特性
在学习 C++1x 之前,我们先了解一下从 C++11 开始,被弃用的主要特性:
注意:弃用并非彻底不能用,只是用于暗示程序员这些特性将从未来的标准中消失,应该尽
量避免使用。但是,已弃用的特性依然是标准库的一部分,并且出于兼容性的考虑,大部分
特性其实会『永久』保留。
• 不再允许字符串字面值常量赋值给一个 char *。如果需要用字符串字面值常量赋值和初始化一个
char *,应该使用 const char * 或者 auto。 cpp char *str = "hello world!"; // 将出现弃用警告
• C++98 异常说明、unexpected_handler、set_unexpected() 等相关特性被弃用,应该使用 noexcept。
• auto_ptr 被弃用,应使用 unique_ptr。
• register 关键字被弃用,可以使用但不再具备任何实际含义。
• bool 类型的 ++ 操作被弃用。
• 如果一个类有析构函数,为其生成拷贝构造函数和拷贝赋值运算符的特性被弃用了。
8