如果说系统软件是软件领域的皇冠,那么 C++ 就是皇冠上的珍珠。在四十余载的技术变迁中,C++ 不断拓展其应用边界。近年的编程语言排行榜上,C++ 一骑绝尘超越 Java,并在今年六月领先 C 语言,居编程语言排行榜第二位。同时,随着大模型重塑计算范式和开发范式,业界对软件安全性的重视前所未有,软件开发迎来全新的篇章。
在这样的背景下,12 月 5-6 日的「2024 全球 C++ 及系统软件技术大会」 邀请C++之父、美国国家工程院、ACM、IEEE 院士 Bjarne Stroustrup 跨洋连线,发表主题演讲《重新认识 C++:跨世纪的现代演进》,并在炉边谈话环节同与会者展开了一场精彩的对话。
在这场由 CSDN 高级副总裁李建忠与 Codeplay 技术副总裁 Michael Wong 主持的一小时炉边对话中,Stroustrup 在纽约的家中,展现出了一位技术领袖的深邃思考,回答了与会者提出的一系列关键问题。这些问题涵盖了技术选择、工程实践、人才培养等多个维度,字里行间流露出他对编程语言、软件系统的深刻理解,以及对技术演进规律的独到见解。
核心议题
从贝尔实验室到 AI 时代的技术沿革
当代软件开发中的安全实践
编程语言的设计哲学与取舍
人工智能时代的计算架构变革
回应白宫与 Rust 社区对 C++ 安全性的质疑
新语言的兴起对社区生态的影响
C++ 标准演进中的代际更迭
新一代程序员的成长之道
第一问:如何看待 C++ 被质疑“不够安全”?
Michael Wong:在您的演讲中,您详细探讨了 C++ 的安全规格配置和指南。与现代强调安全特性的编程语言(如 Rust)相比,C++ 常被批评“不够安全”。您如何看待这种观点?C++ 在维持自身特色的同时,正在采取哪些措施来应对这些挑战?
Bjarne Stroustrup:如果我们采用现代 C++ 的编程方式,严格遵循《C++ 核心指南》(The C++ Core Guidelines),很多安全问题就不会出现。举个例子,我已经很多年没有遇到未被捕获的数组越界问题了。在教学实践中,尽管我现在较少亲自授课,但当其他教师使用我的教材时,我都建议使用范围检查库。我们会确保所有操作都有范围检查保护,因为没有人愿意看到学生们遭遇那些完全可以避免的缓冲区溢出错误。所以基本原则很简单:不要固守旧的编程方式,要拥抱现代 C++,它是安全的。
我们的终极目标是实现类型安全和资源安全,现在这个目标已经触手可及。当前的主要挑战在于缺乏完善的施行机制。虽然我们已经有了一些执行机制,但我们希望能做得更好,并将其标准化。这正是我目前的工作重点——将配置文件的概念引入语言,并建立初始的配置文件集。一旦这项工作完成,C++ 的安全性将超越大多数所谓的现代语言。说实话,那些现代语言也并不像它们宣称的那样安全,它们的安全保证往往是不完整的。比如说,它们缺乏资源安全性。在这些语言中,仅仅通过泄漏文件句柄或线程句柄就可能导致系统崩溃。这显然不是我们想要的结果。而且,这些标榜安全的语言在处理一些底层任务时,比如硬件操作、设备驱动程序开发、系统调用等,往往还是要依赖 C 语言。而 C++ 本来就应该能够处理这些工作,这是它的核心职责之一。因此,我们不能也不应该把这些工作交给其他语言。诚然,这使得提升 C++ 的安全性变得更具挑战性,但这个目标是可以实现的。
第二问:C++ 真的过于复杂了吗?
李建忠:C++ 的复杂性一直是业界争论的焦点。在您的演讲中,您展示了现代 C++ 如何实现更高的安全性、更好的简洁性和更快的性能。但很多人,特别是新手,仍然觉得 C++ 过于复杂。您如何看待这种观点?您认为应该如何提升 C++ 的易用性?
Bjarne Stroustrup:这个问题值得仔细思考。首先,我们要认识到,很多对 C++ 的批评并不那么客观公正。比如,有些批评针对的是一些 C 语言风格的用法,而这些用法在过去 20 年里就已经被优秀的 C++ 程序员摒弃了。当然,我也承认 C++ 确实很复杂,如果有人试图掌握它的所有细节,学习过程必然会很困难。我经常遇到程序员说“我想了解所有的东西”,但我总是告诉他们,这没有必要,我自己也不需要知道所有细节。这正是为什么我们有 CppReference(cppreference.com) 这样的参考资料,当需要查询某个标准函数的具体参数时,随时可以去查阅。
我认为更重要的是理解语言的基础原理,掌握那些能够帮助我们更好地解决问题、开发软件的核心功能。我们应该专注于在这些基础特性和核心库的框架内工作。这也是我们制定《C++ 核心指南》并在此基础上发展配置文件的原因,我们希望帮助开发者专注于 C++ 最安全、最实用、最易维护的部分。之前我也提到过,开发者们一方面要求语言简单,另一方面又需要更多特性,同时还想保持兼容性。在这三个诉求之间找到平衡确实很有挑战。
第三问:C++ 的哪些发展超出了您的预期?
Michael Wong:回顾 C++ 从“带类的 C”(C with classes)到今天的发展历程,什么最让您感到意外?现在的一些应用场景是否超出了您最初的设想?
Bjarne Stroustrup:最让我感到惊讶的是 C++ 真的发展到了今天这样的规模。说实话,我最初并没有打算开发一门通用编程语言。我的初衷很简单,就是想编写一些代码,想要提前十年实现第一个 Unix 集群。但事情的发展出乎意料,我的同事们开始使用这门最初叫“带类的 C”的语言,后来它被命名为 C++。这对我来说是个巨大的惊喜。要知道,我们没有做任何宣传和营销,C++ 就这样自然地成长起来了。
如果看增长曲线,会发现它是指数级的——在最初的 10 到 11 年间,每七个半月 C++ 的用户数量就翻一番。这太令人惊讶了,不过当时我忙于确保一切正常运转,没有太多时间去思考这些现象。
后来另一个转折点出现在 2000 到 2005 年间,C++ 社区出现了萎缩。这其实不难理解,因为当时美国政府、微软、Sun 都在大力推广其他编程语言。但更有趣的是接下来发生的事:这个下行趋势最终被扭转了。如果看今天的数据,我们又看到了一个指数增长曲线。虽然增长速度不再是每七个半月翻一番(具体数字我也没有相关数据来估计),但分析表明,这种反弹有其深层原因:开发者们不太愿意被限制在专有语言中。他们希望能够在所有平台上工作,希望同样的代码能运行在 Windows、Unix、Linux、Android 等各种环境中。虽然各个平台的拥有者都在推广他们自己的语言,但 C++ 这样能在各处都表现良好的语言反而成为了理想的解决方案。
与此同时,硬件发展也遇到了瓶颈。处理器速度不再持续提升,单线程性能停滞不前,有时甚至出现下降。在这种情况下,C++ 的优势再次凸显:优秀的 C++ 程序员能够实现比硬件升级更显著的性能提升,这也是推动 C++ 重新崛起的重要因素。
回过头来看语言特性,构造函数/析构函数这对配套技术,以及由此衍生的 RAII(资源获取即初始化),它们的重要性远超出了我最初的预期。这些特性是我在开发“带类的 C”的最初一两周就加入的,当时只是觉得显然需要它们,因为我有操作系统开发的背景。后来我才知道其他语言既没有多个构造函数,也没有析构函数这样的概念。但事实证明,这成为了 C++ 最有用、最成功的技术基石,也是解决许多性能问题的关键。
第四问:大语言模型将如何影响 C++?
李建忠:大语言模型正在给软件行业带来一场技术革命。您认为它会重塑编程语言吗?对 C++ 会产生怎样的影响?
Bjarne Stroustrup:我首先要声明,我并非 AI 大语言模型领域的专家。说到我与 AI 唯一的渊源,可能就是 TensorFlow 这类 AI 工具是用 C++ 开发的这一点了。从某种意义上说,C++ 构成了当前 AI 技术的基础设施,这本身倒是一个意想不到的发展。我本该更早提到这一点的,但我对 AI 领域的了解确实有限。
不过我相信,大语言模型确实能帮助开发者处理许多重复性的日常工作。同时,我也认为(虽然这只是一种直觉,没有具体证据支持),仍然会有大量工作需要人的创造力,特别是在处理那些 AI 模型训练数据中未曾出现过的新问题时。
第五问:过往版本中最自豪和最遗憾的设计决策是什么?
Michael Wong:回顾 C++ 几十年的发展历程,您最为满意的设计决策和特性是什么?有没有一些决策,如果重来一次,您会采用不同的方式?
Bjarne Stroustrup:我最自豪的就是类系统的设计:简单的类、具有 public 和 private 访问控制的类、带有构造函数和析构函数的类,这些特性最终让开发者能够完全掌控对象的生命周期。现在回想起来,我确实应该为此感到自豪。虽然当时这些设计看起来水到渠成,但实际上不同的编程语言在实现这些概念时采取了截然不同的方式。
另一个重要的决策是关于泛型编程的。我很早就意识到了它的重要性,但最初的尝试完全走错了方向——我试图用宏来实现它。直到 1988 年左右,我才明确意识到必须在语言层面提供对泛型编程的支持。这种支持必须是类型系统的有机组成部分,必须与作用域系统深度整合,必须能够构建出与手写代码完全等效的类型。
我清楚地知道实现这个目标需要三个关键要素。首先,我需要一个超越我想象力的表达系统——我常常说,我想要一个能做到比我想象更多事情的语言特性。其次,它必须具有足够高的性能,让使用者负担得起。要知道,仅仅支持某个特性是不够的,你必须让目标用户群能够负担得起使用它的成本。这也是为什么我从未专注于最顶级超级计算机的原因,因为我深知大多数用户无法负担那样的硬件。第三个要素是良好的接口。说到接口,我其实是把函数参数声明和类型检查引入 C 语言的人。现在任何 C 程序员都在使用这些特性。
这也是为什么我觉得 C 和 C++ 之争非常荒谬。事实上,我从未与 Dennis Ritchie 或 Brian Kernighan 有过任何争执,现在我还经常和 Brian 一起喝酒聊天。那些争论通常来自某些偏执的拥护者,而不是真正理解技术本质的人。
回到泛型编程,在 1988 年到 90 年代初期,我一直在努力实现这三个目标,但始终未能同时达成。考虑到 C++ 的定位,我决定先确保通用性和性能,暂时放弃完美的接口。直到后来与 Gaby Dos Reis 合作,我们才找到了现今概念系统的基础,也就是现在这套泛型编程支持机制。这些工作可以追溯到 1985、86 年,当时我们正在构建各种需求规范。不过,这些成果用了 15 年才被标准委员会接受。
第六问:如何应对 AI 时代的硬件架构变革?
李建忠:AI 技术不仅推动了软件的变革,还带来了计算架构的重大改变,从传统 CPU 到神经网络架构,再到 GPU、NPU 等新型处理器。作为一门系统级语言,C++ 将如何应对这些架构上的变革?
Bjarne Stroustrup:首先,我要再次强调,我并非这些领域的专家。虽然我刚刚阅读了谷歌最新 TPU 的相关资料,但这并不是我的专业领域。
从语言的角度来看,C++ 拥有一个已经存在了 50 年的内存访问模型(这里算上了 C 语言的时间)。这个模型本质上是一种抽象:实际的硬件并不是简单的对象和指针序列,但这种抽象模型在过去几十年中已经证明了它的价值和适应性。
对于未来的发展,我会持续关注,但如果需要做出调整,这个工作可能会由其他人来完成。不过,我有一个预测:TPU、GPU 这类专用处理器最终可能会被证明是位于编程语言层面之下的实现细节——这不仅适用于 C++,也适用于其他语言。我们可以通过合适的内部指令将语言层面的抽象映射到这些硬件设施上。
这让我想起了 C++ 发展历史上的一个类似情况。我曾多次面临压力,要求在语言层面直接支持并发。但我始终抵制这种做法。这种坚持源于我的经验:我的博士研究课题是分布式系统,从中我认识到至少有 25 种方式可能会把事情搞砸。换句话说,为了解决少数特定用户的问题,却可能让大多数用户陷入困境。
因此,我选择了一个不同的策略:通过库来实现这些功能,只在确实无法在库中实现的情况下,才在语言层面提供必要的内部支持。如果让我对 AI 硬件的情况做个预测,我认为这个策略在这里同样适用。
第七问:C++ 中有哪些特性被开发者严重误解或低估了?
Michael Wong:基于您现在的视角,C++ 中有哪些特性被开发者严重误解或低估了?我们应该如何纠正这些认识?
Bjarne Stroustrup:异常(exception)无疑是最典型的例子。我注意到很多 C++ 代码都在以一种过于底层的方式编写,开发者过分依赖于错误码的测试,而这种方式总是容易出问题:要么忘记进行错误处理,要么实现的代价过高。有一种普遍的误解认为异常处理,无论是抛出还是不抛出异常,都会带来很大的性能开销。但实际上,异常处理的设计初衷是用于真正的异常情况,可能是百万次调用中才会出现一次的场景。相比之下,如果你选择系统地测试错误码,就必须在每两个函数调用之间传递额外信息并进行检查,这意味着每次函数调用都会带来测试开销和额外的数据开销。
这种做法存在根本性的问题。而且在某些场景下,比如运算符重载或构造函数中,使用错误码根本就不可行。这会导致代码表达变得非常糟糕,并在对象中引入多余的测试逻辑和异常状态。我认为整个社区在异常处理这个问题上都错过了一个重要的机会。
当然,这种情况的出现是有原因的。问题在于存量代码:很多项目中都有大量的旧式 C 风格代码,到处都是指针,需要手动管理内存的释放和资源的解锁。如果这些代码没有良好的结构,就会变成“意大利面条”式的代码,这种情况下要正确使用异常处理确实很困难。
第八问:职业生涯的哪些经历塑造了您对编程的理解?
张银奎(系统内核专家):能分享一下您的职业发展经验吗?在您的职业生涯中,哪个阶段最重要,我们能从中学到什么?
Bjarne Stroustrup:这些年来,我一直太专注于工作,很少有时间回顾和思考。不过我想,最重要的应该是我所学到的知识,这些收获一部分来自大学时期,一部分来自贝尔实验室。在剑桥大学时,我遇到了几位很好的老师,其中 David Wheeler(世界上首个汇编器的实现者)就是编程领域真正的先驱之一。后来在贝尔实验室,我置身于一个非常好的环境中,那里有很多杰出的人才,比如 Brian Kernighan(Unix 共同开发者)、Alfred Aho(《龙书》作者)、Douglas McIlroy(Unix 共同开发者),还有大家都熟悉的 Dennis Ritchie(C 语言之父)。我在那里学到了很多东西。
他们教会我辨别什么是值得做的,以及该如何去做。特别是 Brian,他教会了我很多写作方面的技巧。我现在的写作方式,就是始终围绕具体的示例,并对这些示例进行分析和讲解。因为我发现,如果只给出示例,人们往往会误解其含义;但如果只讲理论,人们又很难付诸实践。所以两者的结合很重要,这是我从 Brian 那里学到的经验。
在贝尔实验室的工作也让我接触到了大量实际问题。在最初的十年里,我每年都会把 C++ 应用到不同的实际项目中,差不多每年有 10 个项目。这些项目带来的反馈对 C++ 的发展和我个人的成长都很有帮助。因为任何好的工程都需要建立在实践反馈的基础上,而不是纯粹的理论。
所以,虽然给建议并不容易,但既然你问起来,我的建议是:要努力和那些能指导你、帮助你的优秀人才共事,同时要主动去寻找那些值得解决的实际问题。
第九问:重要贡献者转投新语言项目,C++ 社区会因此分裂吗?
许传奇(阿里云开发工程师):我对 C++ 生态系统目前的发展方向有些担忧。以 Carbon 为例,这个由谷歌两年前启动的项目,其主要开发者都曾是 Clang 和 C++ 的核心贡献者,但现在他们把精力转向了新语言的开发。同时,苹果也在将部分 C++ 团队转向 Swift 的 C++ 互操作性开发。最近,Sean Baxter 还发表了一篇关于“安全 C++”(Safe C++)的论文,提倡使用内存安全语言(如 Rust)。这些趋势是否意味着 C++ 生态系统正在变得更加分散?您对此有什么看法?
Bjarne Stroustrup:这是个很大的话题。在计算机科学和计算领域,开发新编程语言似乎成了一种普遍的追求。与改进现有语言相比,创造新语言显得更加引人注目——你很难通过改进现有语言成为技术明星,但开发一门新语言则更容易获得关注。问题在于,现在太多人都在这么做,就像我经常收到高中生询问如何开发编程语言,而我总是反问他们:为什么要这样做?即便是标准委员会的成员,有些人也开始厌倦了维护和改进现有代码的工作。
我们看到很多新语言都借鉴了 C++ 的理念,Swift 就是一个很好的例子。至于 Carbon,我对它的前景持保留态度。它给人的感觉仅仅是在说“我们要做 C++ 正在做的事情,但要做得更好”。这种策略通常到最后都失败了。而根据我的经验,所谓的“更好”往往只是意味着更加传统,而不是真正的创新。
当然,他们可能会建立起某些优于 C++ 的生态系统。但有趣的是,我注意到一些曾经离开的组织现在又回到了 C++ 标准委员会。比如 Chandler Carruth 最近就发表了一篇出色的论文,探讨如何增强 C++ 来消除缓冲区溢出等问题,这表明他并没有完全转向 Carbon 的开发。
目前确实有三到五种新语言在同时发展。如果它们都取得成功,无疑会导致开发者社区的分裂,就像那些仅关注内存安全的人提出的七种不同语言一样。将一个语言社区分割成五到七个难以互相沟通的小群体,这对任何人都没有好处。
特别值得一提的是 Sean Baxter 提出的 Safe C++,这个提案相当不合理。它实质上是要求开发者完全按照 Rust 的方式来编程——但我认为,如果你想用 Rust 的方式编程,那么你就应该使用 Rust(If you want Rust, go to Rust)。他最近甚至建议要对 C++ 做 25 处不同的改动,还要放弃 C++ 标准库转而使用 Rust 的库,这太离谱了。
第十问:您对美国政府的安全警告有何回应?
吴咏炜(Boolan 首席咨询师):您如何看待白宫提出的从 2026 年开始禁止使用 C++ 的建议?您认为 C++ 社区应该如何应对?
Bjarne Stroustrup:这个判断显然出于对技术的无知,甚至有些恶意(very unenlightened and quite nasty)。他们的观点过于片面,并声称这是一个安全问题。但实际上,安全性是一个多维度的概念。举个例子,如果有人想要入侵一个计算机系统,缓冲区溢出可能并不是他们的首选方案。他们可能会选择 SQL 注入这样的攻击方式,或者直接从物理层面入手。但当我们试图就这些问题展开讨论时,却发现很难得到真正的回应——他们似乎选择性地忽视了我们能够采取的技术对策。这让我不禁怀疑他们背后的真实动机。
不过,C++ 社区经历过类似的挑战。我们成功地度过了 Java 带来的冲击,也经受住了 Ada 的挑战。让我们拭目以待这次的情况如何发展。作为一个技术人员而非政治人物,我选择将精力集中在技术层面的改进上。目前我正在致力于完善《C++ 核心指南》,并推进规格配置的施行。
我可以明确地说,如果有足够的资源支持,我们完全有能力在一年内解决 C++ 中的悬空指针问题和未定义行为。问题不在于技术可行性,而在于资源的限制。
第十一问:如何说服管理层升级 C++ 版本?
现场观众:我们团队正在开发一个新的交易系统,但仍在使用 C++11 标准。我们发现很难说服非技术背景的管理层升级到新的 C++ 标准。您对这种情况有什么建议吗?
Bjarne Stroustrup:说服管理者确实很难。有些管理者可能因为十年前写过代码就认为自己仍然精通技术,还有一些管理者可能从未担任过开发工作,这都会使沟通变得更加困难。
我认为唯一的方法是保持对话和倾听。要让他们有机会充分表达他们的想法和顾虑,理解他们的决策考虑。在这个过程中,你可能会经常听到类似“我们就要这个特定的方案”或“我们要完全照搬那个系统”这样的表态。这很正常,因为用户(包括管理层)总是倾向于要求与他们熟悉的东西相类似的方案。关键在于通过持续的沟通和讨论,逐步梳理出他们真正的需求和目标。这需要时间和耐心,可能还需要反复的协商。我认为这是与管理层打交道最实用的策略。
第十二问:新特性落地还要等多久?
现场观众:对于网络反射、模块、概念等 C++ 20 的新特性,业界期望很高。但有观点认为这些特性可能需要很多年,甚至 20 年才能真正投入使用。您如何看待 C++ 标准与实际实现之间的这种落差?
Bjarne Stroustrup:实际情况比很多人想象的要乐观。这些特性的实现其实已经存在,而且主流编译器的支持都相当不错,并且在持续改进中。确实,Clang 在概念和模块这两个特性上初期有些滞后,主要是因为他们最初对这些特性的可实现性持怀疑态度。但事实证明这些特性是完全可以实现的,现在 Clang 的支持也在不断完善。
你完全不需要等待十年那么久。实际上,只要使用最新版本的编译器,你现在就能开始尝试这些特性。已经有开发者在各大主流编译器的生产环境中使用这些新特性了。
第十三问:C++26 的安全特性何时可用?
现场观众:C++26 标准有许多关于安全性的特性。对于我们开发者来说,什么时候能使用这些安全特性呢?
Bjarne Stroustrup:我其实不太明白你说的“安全性”具体指什么。我之前谈到的规格配置(profiles)是对这个问题的直接回应。此外还有一些被定位为安全特性的功能,比如契约(contract)。我也很希望能看到函数式风格的模式匹配,但这两个特性都不能保证会出现在 C++26 中。如果其中一个或两个都没能进入标准,我也不会感到意外。而且我不清楚你还在考虑哪些其他特性。
第十四问:给年轻程序员的关键建议是什么?
李建忠:作为世界上最杰出的程序员之一,您为软件工程领域做出了重要贡献。全世界的程序员,包括中国的开发者们,都非常敬佩您。他们希望能成为像您这样优秀的程序员。基于您丰富的职业生涯经验和智慧,您能给这些程序员一些建议吗?
Bjarne Stroustrup:这可能会让我感到有些难为情,因为我经常被问到这个问题,也许这说明我正在变老。不过认真想来,我认为最重要的建议是:不要以为自己能预见未来的发展。你必须时刻准备应对变化,必须持续学习并积累广泛的知识。不要一味追逐当前最热门的技术,因为这些技术可能几年后就会过时。相反,要着力打造一个扎实而广泛的知识基础,这样当机会出现时,你才能识别它并具备把握它的能力。总之,保持开放的心态,不要对未来抱有过于确定的预判。