Thriving in a Crowded and Changing World C++ 2006–2020 (11 回顾)

备注:完整pdf

编程语言设计的最终目标是改进程序员在交付有用应用程序时的思考和工作方式。 有些语言被认为“只是实验性的”,但是一旦将一种语言用于与语言本身无关的工作,语言设计者就会对其用户负责。 正确性、适当性、稳定性和足够的性能成为重要的问题。 对于 C++,这发生在 1979 年,仅仅过了 6 个月。 C++ 已经蓬勃发展了 40 年。 为什么?如何做到?

我之前的 HOPL 论文 [Stroustrup 1993, 2007] 从 1991 年和 2006 年的角度提供了答案。除了语言特性和库组件之外,自那时以来发生的变化主要是标准委员会的作用和影响 (ğ3)。

在这里,我考虑

  • 11.1:C++ 模型
  • 11.2:技术上的成功
  • 11.3:需要工作的领域
  • 11.4:经验教训
  • 11.5:未来

11.1 C++模型

C++ 成为要求苛刻的应用程序的主要语言,并且在某些领域占主导地位。它没有认真的商业支持,也没有营销。许多现代语言复制了它的特性和思想 (ğ2.4)。贡献的关键语言技术领域是:

  • 对内置类型和用户定义类型同等支持的静态类型系统 (ğ2.1)
  • 值和引用语义(4.2.3)
  • 系统的和一般的资源管理 (RAII) (ğ2.2)
  • 支持高效的面向对象编程 (ğ2.1)
  • 支持灵活高效的通用编程 (ğ10.5.1)
  • 支持编译时编程 (ğ4.2.7)
  • 直接使用机器和操作系统资源 (ğ1)
  • 通过库的并发支持(通常使用内部函数实现)(ğ4.1) (ğ9.4)

C++ 为软件提供了一种不同的——而且对于许多应用领域来说更好——与目前占主导地位的“托管”模型相比,它依赖于垃圾收集器和广泛的运行时支持,这些模型以 Java、C#、Python 和 JavaScript 等语言为代表(2.3 )。 “更好”的意思是“编写更简单,更可能正确,更易于维护,使用更少的内存,使用更少的能源,更快”。

贡献的领域是相互支持的。 例如

  • 引用语义(例如,指针和智能指针)支持有效实现具有值语义的高级类型(例如,jthreadvector)。
  • 内置和用户定义类型的统一规则简化了泛型编程(内置类型不是特例)。
  • 编译时编程使一系列抽象技术能够有效利用硬件。
  • RAII 允许使用用户定义的类型,而无需采取特定操作来支持其实现对资源(包括非内存资源)的使用。

11.2 技术性成就

C++ 成功的根本原因很简单:它填补了编程领域的一个重要领域:

需要高效使用硬件并管理显著复杂性的应用程序。

如果您能负担得起 25% 或 99% 的硬件容量,那么不乏可供选择的编程语言和环境,如果您的低级需求仅代表几千行低级代码、C 或汇编程序将服务。 40 年来,C++ 的“利基”足以保持其社区的发展。

这是 C++ 的现代(2014)摘要:

  • 直接映射到硬件
    • 指令和基本数据类型
    • 最初来自 C
  • 零开销抽象
    • 具有构造函数和析构函数的类、继承、泛型编程、函数对象
    • 最初来自 Simula(它不是零开销)

Simula 开创了抽象机制和灵活的类型系统,但它们在运行时间和空间上都付出了沉重的代价。与 1995 年对 C++ 的描述 (ğ2.1) 相比,重点已从编程技术转移到问题领域。与语言设计相比,这更多是解释风格和人们兴趣的差异。这两个摘要现在和当时都是准确的。

在过去几十年的基础上,2000 年代的关键技术进步包括:

  • 内存模型 (ğ4.1.1)
  • 类型安全的并发支持:线程和锁 (4.1.2)、并行算法 (8.5)、连接线程 (9.4)
  • 类型推导:auto (?4.2.1)、概念 (?6)、模板参数推导 (?8.1)、可变参数模板 (?4.3.2)
  • 使用的简化:auto (?4.2.1)、range-for (?4.2.2)、并行算法 (?8.5)、range (?9.3.5)、lambda (?4.3.1)
  • 移动语义 (ğ4.2.3)
  • 编译时编程:constexpr (?4.2.7)、编译时循环 (?5.5)、保证编译时评估和容器 (?9.3.3)、元编程 (?10.5.2)
  • 泛型编程:STL (ğ10.5.1)、概念 (ğ6)、用户定义类型作为模板参数 (ğ9.3.3)、lambda (ğ4.3.1)
  • 元编程 (ğ10.5.2)

它们都与零开销原则有关,但最后两个有点令人惊讶,因为 C++ 在 2006-2020 时间范围内对它们的支持不完整。

以上这些都不会导致 C++ 陷入不兼容的方言或成为您无法长期依赖的东西:

  • 稳定性和兼容性至关重要 (ğ1.1) (ğ11.4)

新特性(从 C++11 开始)导致了标准库(例如,unique_ptr、chrono、format 和 scoped_lock)和许多其他库的改进。

C++ 的目的是成为构建应用程序的工具,因此 C++ 的许多伟大应用程序,例如 (?2.3) 和 (?10.1) 中提到的那些,都是 C++ 的真正成功之处。

11.3 需要改进的领域

没有一种语言是适合所有人和所有事物的。没有人比懂多种语言、认真使用一种语言并尝试支持它的人更了解这一点。阻碍进步的往往不是简单的无知。相反,重大改进的主要障碍是缺乏方向、缺乏开发资源以及害怕破坏现有代码。

C++ 因诞生于现代 IDE、构建系统、GUI 系统和 Unicode 之前而受苦。我希望 C++ 能慢慢赶上。例如:

  • 工具:从 C 开始,在字符和词汇标记方面指定的语义以及使用 #include 和宏组织的源代码一直是有效工具构建的主要障碍。模块应该会有所帮助 (ğ9.3.1),并且可以为 C++ 设计一个合理的内部表示 [Dos Reis and Stroustrup 2009, 2011]。
  • 教育:今天教授的 C++ 仍然大多过时和向后看 (ğ2.3)。核心指南 (ğ10.6) 是实现实践现代化的一种方法。 WG21 的教育研究小组 (ğ3.2) 和许多以教育为导向的会议报告 (ğ10.3) 表明,这些问题得到了重视并得到了解决。
  • 打包和分发:C++ 诞生在由独立开发和维护的组件构成软件很常见的时代之前。今天,有 C++ 的构建系统和包管理器。然而,没有一个是标准的,有些很难用于简单的任务,而另一些则不能泛化以应对使用 C++ 构建的大规模系统。我的 2017 CppCon 主题演讲挑战 C++ 社区解决这个问题 [Stroustrup 2017c],我认为我们正在看到进展。此外,C++ 社区缺乏一个标准的地方来寻找有用的库。 Boost [Boost 1998ś2020] 就是为了解决这个问题,GitHub 正在成为一个通用存储库,但要让相对新手找到、下载、安装和运行几个主要库,还有很长的路要走。
  • 字符集和图形:C++ 语言和标准库依赖于 ASCII,但大多数应用程序使用某种形式的 Unicode。 WG21 现在有一个研究小组来寻找标准化 Unicode 支持的方法 (ğ3.2)。缺乏标准图形和 GUI 是一个更难的问题。
  • 清理旧的烂摊子:这太难了。例如,我们知道内置类型之间的隐式缩窄转换会导致无穷无尽的问题 (ğ9.3.8),但是有数千亿行 C++ 代码以不可预测的方式依赖于这些转换。通过添加更多现代功能来替换旧功能来进行改进的尝试很容易陷入 N+1 问题 (4.2.5)。改进的工具(例如,静态程序分析和程序转换)提供了希望。

大型语言社区面临的挑战多种多样,无法通过单一的简单解决方案解决。这不仅仅是语法、类型理论或基本语言设计的问题。有些问题是商业性的。在工业规模上取得成功所需的技能范围令人生畏。时间会证明 C++ 社区是否会掌握所有这些,以及更多。我是适度乐观的,因为在所有领域都有倡议 (ğ3.2)。

11.4 经验教训

C++ 由一个成员众多且不断变化的大型委员会控制 (ğ3.2)。所以除了技术问题之外,我们还必须考虑在语言发展过程中什么起作用:

  • 问题驱动:C++ 的开发应该由特定现实世界问题的需求驱动。
  • 简单:C++ 应该从简单、高效、易于使用的解决方案泛化而来。
  • 高效:C++ 语言和标准库应遵循零开销原则。
  • 稳定:不要破坏我的代码!

大多数(全部?)C++ 最成功部分的开发都遵循了这些“经验法则”。它们自然会限制语言的范围,但这很好。 C++ 并不意味着对所有人都适用。此外,这些原则迫使 C++ 基于现实世界的挑战相对缓慢地发展,并使其能够从反馈中受益。另请参阅 The Design and Evolution of C++ [Stroustrup 1994] 和我的 HOPL2 论文 [Stroustrup 1993] 中的其他“经验法则”。有连续性。
相比之下,没有明确关注更大社区问题的设施通常会失败:

  • 仅限专家:设施必须从一开始就满足所有专家的需求。
  • 模仿:我们需要这个工具,因为它在X语言中很流行
  • 理论:语言理论说一种语言必须具有这个特性。
  • 革命性:此功能非常重要,我们必须打破兼容性或弃用“糟糕的旧方式”做事。

我的结论是,及早设定方向和期望是必不可少的。之后,会有太多意见分歧的人无法就一套连贯的想法达成一致。

给定一个方向和一组原则,一种语言可以根据反馈、用户体验、实验和理论作为工具来发展。这是与无原则的实用主义或教条主义的理想主义相反的良好工程。

C++ 标准委员会的章程几乎只关注语言和库设计。这是限制性的。动态链接、构建系统和静态分析等重要主题大多被忽略。这是一个错误。工具是软件开发人员世界的重要组成部分,如果它们不是语言设计的外围,那就太好了。

对多样化想法的热情是危险的。在 2018 年的论文 [Stroustrup 2018d] 中,我列出了 51 个最近的提案:

“我列出了我认为有可能显著改变我们编写代码的方式的论文,因此每篇论文对教学、维护和编码指南都有重要意义。许多也对实现有影响。
个别地,许多(大多数?)提案都有意义。他们一起疯狂到危及 C++ 的未来。”

那篇论文的标题是“记住瓦萨!”。瓦萨号是一艘宏伟的 17 世纪瑞典战舰,由于其设计添加较晚和测试不足,首航时在斯德哥尔摩港沉没。在 1990 年代,委员会经常提醒自己“瓦萨”,但在 2010 年代,这一教训似乎已被遗忘。

为了对委员会流程施加组织限制,DG 提出了“C++ 程序员权利法案”[Dawes 等人。 2018]:

  1. 编译时稳定性:新版本标准中行为的每一个重大变化都可以被前一版本的编译器检测到。
  2. 链接时间稳定性:避免 ABI 损坏,除非在极少数情况下,这将得到充分记录并有书面理由支持。
  3. 编译器性能稳定性:更改不会显着增加现有代码的编译时间成本。
  4. 运行时性能稳定性:更改不会显着增加现有代码的运行时成本。
  5. 进展:标准的每次修订都会为一些重要的编程活动或社区提供更好的支持。
  6. 简单性:标准的每次修订都会简化一些重要的编程活动。
  7. 及时性:标准的每一次修订都将按照公布的时间表准时发货。

未来几十年将展示这是如何实现的。

11.5 未来

就近期而言,C++20 将像 C++11 一样为 C++ 社区带来福音。在 2020 年 2 月于布拉格举行的会议上,委员会最终确定了 C++20,它还投票支持 Ville Voutilainen 的“C++23 的大胆计划”[Voutilainen 2019b]:

“努力在 C++23 中实现以下内容”:

  • 对协同程序的库支持 (ğ9.3.2)
  • 模块化标准库 (ğ9.3.1)
  • 通用异步计算模型(执行器)(8.8.1)
  • 网络 (8.8.1)

请注意,重点是库。 “也在以下方面取得进展”:

  • 静态反射设施 (ğ9.6.2)
  • 函数式编程风格的模式匹配 (8.2)
  • 合同 (ğ9.6.1)

鉴于有关这些主题的工作相当先进,委员会很有可能会取得最大的成就。一大群狂热者可以开发并达成一致的其他内容是不太可预测的。在接下来的几年里,指导小组(我是其中的成员)提到了一些有希望的进一步工作领域[Hinnant et al. 2020]:

  • 改进的 Unicode 支持
  • 支持简单的图形和简单的用户交互
  • 支持新型硬件
  • 探索改进的错误处理风格和实现

在委员会之外,我希望在构建系统、包管理和静态分析(10.4)方面取得重大进展。

除此之外 - 未来五年,十年或更长时间 - 我的水晶球变得有点阴暗。对于那个时间尺度,我们需要查看基础知识而不是特定的语言功能。我希望标准委员会能够吸取经验教训 (ğ11.4) 并专注于基本原则 (ğ11.1):

  • 追求完全资源安全和类型安全的 C++ 的目标
  • 很好地支持各种硬件
  • 保持 C++ 的稳定性(兼容性)记录

保持稳定性需要关注兼容性,并抵制尝试通过添加大量“完美”功能来替换不完美或不流行的旧方式来从根本上改进 C++ 的冲动。新功能总是会带来惊喜(有些令人愉快,有些不那么令人愉快),而且旧的功能不会简单地消失。“记住瓦萨!”[Stroustrup 2018d] (ğ11.4)。通常,库、指南和工具是替代语言更改的更好选择。

对于单线程计算,硬件并没有变得更快,因此效率上的优势仍然存在,有效支持各种形式的并发和并行性的压力将增加(2.3)。专用硬件将激增(例如,各种内存架构和专用处理器);这将使可以利用它的语言(例如 C++)受益。唯一比硬件性能增长更快的是人类的期望。

系统变得越来越复杂,因此负担得起的抽象机制的重要性也将增加。对于依赖实时交互的系统,可预测的性能是必不可少的(例如,许多实时系统禁止使用免费存储(动态内存))。

随着我们对计算机化系统的依赖增加和老练黑客数量的增加,安全问题的重要性只会增加。为了辩护,我押注硬件保护和支持更好静态分析的结构化系统,而不是无休止的临时运行时检查和低级代码。

语言和系统之间的互操作性仍然必不可少;很少有主要系统会用一种语言编写。

随着系统变得越来越复杂以及对可靠性的要求不断提高,对设计和编码质量的需求急剧增加。我认为 C++ 已经为此做好了充分的准备,C++23 的计划是进一步加强它。然而,仅靠语言特征并不足以满足未来的需求。我们需要由工具支持的指南,以确保有效使用(10.6)。特别是,我们需要确保完全类型安全和资源安全。这必须体现在教育中。为了蓬勃发展,C++ 需要更好的新手教育材料和一些帮助有经验的程序员掌握现代 C++ 的材料。仅仅展示聪明的技巧和高级用法是不够的,还会通过强化其复杂性的声誉来损害语言。

由于许多原因,我们需要简化 C++ 的大部分使用。 C++ 已经发展到使这成为可能,我预计这种趋势将持续下去(4.2)。改进的优化器 - 能够利用代码中使用的类型系统和抽象 - 有所作为。在过去的几年里,这极大地改变了我优化代码的方式:我从抛弃聪明和复杂的东西开始。这就是错误隐藏的地方,如果我无法理解正在发生的事情,那么编译器和优化器也将如此。我发现这种方法通常会给我带来适度到惊人的性能改进,以及简化未来的维护。只有当这不能给我想要的性能时,我才会求助于高级(也就是复杂的)数据结构和算法。这是 C++ 抽象机制设计的胜利。我期待看到更多用 C++ 构建的令人兴奋的应用程序,并期待看到新的编程习惯用法和设计技术的开发。

我希望其他语言能从 C++ 的成功中学习。如果从 C++ 的演变中吸取的教训仅限于 C++ 社区,那将是可悲的。我希望并期待在其他语言和系统中看到 C++ 模型的关键方面;这将是衡量成功的真正标准。在有限的范围内,这已经发生了 (ğ2.4)。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值