4. C++11:感觉像是门新语言
C++11 [Becker 2011] 发布后,其实现相对来说很快就出现了。这导致了极大的热情,增加了使用,有大量新人涌入 C++ 世界,并进行了大量的实验。C++11 的三个完整或几乎完整的实现在 2013 年面世。我当时的评论被广泛认为是准确的——C++11 感觉像是一门新的语言 [Stroustrup 2014d]。为什么 C++11 在帮助程序员方面做得如此出色?又是如何做到的?
C++11 引入了大量令人眼花缭乱的语言特性,包括:
- 内存模型——一个高效的为现代硬件设计的底层抽象,作为描述并发的基础(§4.1.1)
auto
和decltype
——避免类型名称的不必要重复(§4.2.1)- 范围
for
——对范围的简单顺序遍历(§4.2.2) - 移动语义和右值引用——减少数据拷贝(§4.2.3)
- 统一初始化—— 对所有类型都(几乎)完全一致的初始化语法和语义(§4.2.5)
nullptr
——给空指针一个名字(§4.2.6)constexpr
函数——在编译期进行求值的函数(§4.2.7)- 用户定义字面量——为用户自定义类型提供字面量支持(§4.2.8)
- 原始字符串字面量——不需要转义字符的字面量,主要用在正则表达式中(§4.2.9)
- 属性——将任意信息同一个名字关联(§4.2.10)
- lambda 表达式——匿名函数对象(§4.3.1)
- 变参模板——可以处理任意个任意类型的参数的模板(§4.3.2)
- 模板别名——能够重命名模板并为新名称绑定一些模板参数(§4.3.3)
noexcept
——确保函数不会抛出异常的方法(§4.5.3)override
和final
——用于管理大型类层次结构的明确语法static_assert
——编译期断言long long
——更长的整数类型- 默认成员初始化器——给数据成员一个默认值,这个默认值可以被构造函数中的初始化所取代
enum class
——枚举值带有作用域的强类型枚举
以下是主要的标准库组件列表(§4.6):
unique_ptr
和shared_ptr
——依赖 RAII(§2.2.1)的资源管理指针(§4.2.4)- 内存模型和
atomic
变量(§4.1.1) thread
、mutex
、condition_variable
等——为基本的系统层级的并发提供了类型安全、可移植的支持(§4.1.2)future
、promise
和packaged_task
,等——稍稍更高级的并发(§4.1.3)tuple
——匿名的简单复合类型(§4.3.4)- 类型特征(type trait)——类型的可测试属性,用于元编程(§4.5.1)
- 正则表达式匹配(§4.6)
- 随机数——带有许多生成器(引擎)和多种分布(§4.6)
- 时间——
time_point
和duration
(§4.6) unordered_map
等——哈希表forward_list
——单向链表array
——具有固定常量大小的数组,并且会记住自己的大小- emplace 运算——在容器内直接构建对象,避免拷贝
exception_ptr
——允许在线程之间传递异常
还有很多,但这些是最重要的变化。所有这些都在 [Stroustrup 2013] 中进行了描述,许多信息可以在网上获得(例如 [Cppreference 2011–2020])。
这些表面上互不相干的扩展怎么能组成一个连贯的整体?这怎么可能真正地改变我们写代码的方式,使之变得更好呢?C++11 确实做到了这一点。在相对较短的时间里(算 5 年吧),大量的 C++ 代码被升级到 C++11(并进一步升级到 C++14 和 C++17),而且 C++ 在会议和博客上的呈现也完全改变了。
这种在语言的感觉
和使用风格上的巨大变化,并不是由某位大师级工匠指导的传统的精心设计过程的结果,而是海量建议经由一大批不断变化的个人层层决策过滤后的结果。
在我的 HOPL3 论文 [Stroustrup 2007] 中,我正确地描述了 C++11 语言的许多特性。值得注意的例外是概念
,我会在(§6)中进行讨论。我将不再赘述细节,而是根据它们所解决的程序员需求来描述功能的主题
分类。我认为这种看待提案的方式是 C++11 成功的根源:
- §4.1:支持并发
- §4.2:简化使用
- §4.3:改进对泛型编程的支持
- §4.4:提高静态类型安全
- §4.5:支持对库的开发
- §4.6:标准库组件
这些主题
并不是不相干的。事实上,我猜想 C++11 之所以成功,是因为它相互关联的功能彼此加成,形成了一张精细的网络,可以处理真正的需求。每一个主题里都有我喜欢的特性。我怀疑,我在写作(例如 [Stroustrup 1993, 1994, 2007])和演讲中明确表述了 C++ 的目标,也帮助设计保持了合理的重点。对我来说,衡量每个新特性的一个关键指标是它是否使 C++ 更接近它的理想,例如,是否通过引入该特性能让对内建类型和用户定义类型的支持更加相似(§2.1)。
纵观 C++11,我们可以看到有些改进建议在 2002 年左右就被提出,有不少库也出现得很早,经常是作为 Boost 的一部分 [Boost 1998–2020]。然而,直到 2013 年才有完整的 C++11 实现。在 2020 年,一些组织仍在为升级到 C++11 而苦恼,因为代码库巨大,程序员不思进取,教学方式陈旧,以及编译器严重过时(尤其是在嵌入式系统领域)。不过 C++17 的采用速度明显快于 C++98 和 C++11;并且,早在 2018 年,C++20 的一些主要特性就已经投入生产使用。
直到 2018 年,我仍能看到 C++98 前的编译器被用于教学。我认为这是对学生的虐待,剥夺了他们接触学习我们 20 多年的进展的机会。
对标准委员会、主要编译器厂商以及大多数 C++ 的积极支持者来说已是遥远的过去的东西,对许多人来说仍然是现在,甚至是未来。其结果是,人们对 C++ 到底是什么仍然感到困惑。只要 C++ 继续演化,这种困惑就会持续下去。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论