# 本贾尼·斯特劳斯特卢普：C++

> C++ 设计者谈语言的设计取舍、零开销抽象的理念，以及编程教育与好代码的标准。

- 原标题：Bjarne Stroustrup: C++
- 期数：特别节目
- 发布日期：2019-11-07
- 嘉宾 / 主题：本贾尼·斯特劳斯特卢普
- 网页版：https://lexfridman-cn.pages.dev/ep/bjarne-stroustrup/
- 官方页面：https://lexfridman.com/bjarne-stroustrup/
- 精读字数：约 10265 字（阅读约 23 分钟）

> 本文为 lex.qiaomu.ai 基于原始访谈的 AI 改写中文精读，非官方翻译；引用请注明出处并链接网页版。

你踩下刹车踏板的时候，踏板和刹车片之间没有机械连杆。中间隔着一台计算机。

这台计算机上跑的代码，很多是用一门 1979 年开始写的语言实现的。C++。

YouTube 的大量关键后端组件是 C++ 写的。Google、Facebook、亚马逊、推特、微软的多数应用、多数数据库系统，还有那些在物理世界里真正干活的东西：汽车、机器人、发射进太空的火箭。这些东西的共同点是，出错不能靠"重启一下"解决。

2019 年，Lex Fridman 把这门语言的作者本贾尼·斯特劳斯特卢普（Bjarne Stroustrup）请到播客里聊了一个多小时。这场对话没停在语法特性上，它更像一个人在解释自己四十年的取舍：什么必须快，什么必须可靠，什么宁可不要。

## 第一门真正爱上的语言，和那个算星形的下午

斯特劳斯特卢普写的第一个程序，是大学二年级的事。任务是算出一段曲线的形状，然后把周长上的点连起来，生成星形图案。输出设备是一台纸带打印机。

他学编程算晚的，第二年才正式开始。第一门让他产生感情的语言是 Algol 60。之后的路走得不太顺：Fortran 没让他心动，Pascal 也没有。

> Pascal 总是在挡我的路。（斯特劳斯特卢普）

他转向汇编，觉得那反而更有意思，接着写了大量 BCPL。BCPL 时期是他第一次靠编程赚到钱，硕士学费就是这么付掉的。

真正打开新世界的是 Simula。

Simula 是 Algol 60 的扩展，本来为仿真而做。做这个语言的人顺手发明了面向对象编程、继承、运行时多态。斯特劳斯特卢普在这里第一次意识到一件事：程序的复杂度可以随代码规模线性增长，而不必随规模平方增长。

**你完全可以做到很好的模块化。这对我来说是个惊喜。**

另一个惊喜关于类型系统。Pascal 的类型系统处处跟他作对，Simula 的类型系统比 Pascal 更严格，却处处帮他的忙。这个反差后来成了 C++ 的一条底层信念：类型系统要强，同时必须可扩展、可变形。

## 那个年代的 Pascal，带着一种道德腔调

他解释这个差别的时候说得很直接。Pascal 是 Niklaus Wirth 能为当时的需求设计出的最简语言。它有一种高度说教的语气：如果你能用 Pascal 表达，那就是好的；表达不出来，那就是不好的。

Simula 反过来，鼓励你自己建类型系统。你不必把自己塞进 Wirth 划定的那个世界里，你可以为自己手头的问题现造一套类型。

这已经很接近今天说的领域特定语言（DSL）。你真正在建的，是一组类型以及类型之间的关系，这组关系让你能用贴合应用的方式描述问题。

顺带一个冷知识：所有用 class 这个词表示类型的语言，都是 Simula 的直系或旁系后代。Simula 的设计者是一群数学家，他们不按"类型"思考，想的是集合和元素类，于是把类型叫成了 class。

## 消防车转弯，为什么需要继承

很多人对继承的理解停在教科书上那个"动物→狗→猫"的例子，从来没搞明白它在解决什么问题。斯特劳斯特卢普给了一个他亲眼见过的例子。

你有一个车辆集合：自行车、轿车、消防车、坦克。现在你让它们左转。如果你不知道它们是什么，你得写一大堆判断：如果是自行车，按自行车的方式转；如果是轿车，按轿车的方式转；如果是消防车，按消防车的方式把方向盘打死。

代码会变成一坨巨大的 case 和 if 嵌套。

有了继承，你只需要对着基类说一句"转"。每个具体类型自己知道该怎么转。

> 60 年代有人真拿它去模拟和优化某个地方的紧急救援调度。（斯特劳斯特卢普）

这个例子里藏着一个很硬的需求：你不可能每来一种新车型就重写一遍调度代码。继承和运行时多态之所以值得存在，是因为真实系统会不断长出新东西，而调度逻辑必须稳如磐石。

## 为什么 Lisp 不是他的菜

访谈里 Fridman 提到 Lisp 是自己最喜欢的语言之一，问斯特劳斯特卢普怎么看。回答很诚实：Lisp 当然重要，当然有意思，很多人在里面写代码，然后在要上生产环境的时候，把它重写进 C 和 C++。

他的领域有一组绕不过去的约束：性能、可靠性、可部署性、硬件成本。

> 我不喜欢东西太动态。写一段既完美又灵活的代码，能塞进一台小计算机，还能装进波哥大的电话交换机里，这个概率有多大？（斯特劳斯特卢普）

他举了一个具体场景：某个周日的深夜，波哥大的电话交换机崩了，你发现自己进了调试器。周围有个程序员吗？

概率是零。

他很清楚自己服务的只是少数派。全球七八成的代码不在这种约束下，写 Web 前端和数据分析脚本的人完全有资格享受动态语言带来的速度。但总得有人负责从那些高级而灵活的语言，一路下到硬件。他选了这个位置。

在这个位置上，一门语言的价值不体现在写起来多舒服，而体现在写出来的东西十年、二十年、三十年之后还能在苛刻条件下跑。

## 五门语言，第二门最重要

他说一个专业程序员应该懂至少五门语言。理由跟会不会用它们没关系，学语言这件事本身就是训练。

> 只会一种语言的人，就像一个只待在自己文化里的人，很容易以为自己的活法就是唯一的活法。（斯特劳斯特卢普）

他估计自己懂二十五门左右。他也承认那个年代学语言容易，语言本身小，不用连整套编程环境一起啃。

他随手挑了五门：机器码、C++、一门函数式语言（Haskell 或 ML 都行）、一门能快速出活的语言（JavaScript、Python、Ruby 随便挑一门）。

关于机器码，他给了一个今天写高层代码的人必须记住的判断。手写底层代码换性能这件事已经过去了，C++ 优化器比人聪明。但如果你不懂机器码和机器架构，你根本欣赏不了优化器在做什么。

更实际的一点：**你把缓存弄乱了，性能直接掉一百倍，这个惩罚跟用什么语言无关。**

他说，现在他最喜欢的优化方式，是把代码里那些"聪明的部分"全删掉，看看还跑不跑得快。有时候删完更快。

所以他需要的其实是抽象机制，让他能把代码写得紧凑、写得让优化器看得懂。

## Commodore 64 上的 Pong，和一条不断缩短的代码

他提到 Jason Turner 在 CppCon 上的一场演讲。那个人决定在一台 Commodore 64 上写 Pong。这台机器的特点和今天的微控制器很像：有专用硬件，内存小得可怜，速度慢。

现场直播的过程是这样的：他先用相当直白、相当低层的方式写，然后用 Compiler Explorer 实时看到 C++ 编译成汇编。接着他开始提高抽象层次，用 C++11 的特性，代码变得更干净、更好维护、更短。

它一直在变短。

斯特劳斯特卢普的结论是，他不可能在任何合理的时间内手写出编译器从现代 C++ 生成的那种质量的机器码。他甚至说，**那段看起来像 C 的代码，变成机器码之后反而更丑、更大。**

这个演示的价值在于它把"抽象"从一个审美偏好拉回到了工程事实：能被优化的抽象才有资格存在。

## 刹车上没有机械连杆

回到开头那个画面。汽车刹车踏板和刹车系统之间已经不是直接的机械连接，中间是计算机。这台计算机最好别出错。

现代的汽车要用几百万行代码，自动驾驶和车道保持这类系统更甚。Fridman 提到他跟监管者聊过，那些人对软件安全性极度紧张，因为这些代码最终会做出可能致死的决策。

斯特劳斯特卢普的回答绕开了一个常见的思维陷阱。

> 安全性、性能、保密性，都是系统属性。人们习惯一次只看系统的一个部分，然后说"这块是安全的"。你如果真想要可靠、想要性能、想要安全，你必须看整个系统。（斯特劳斯特卢普）

他甚至反过来讲了一层：把单个零件打磨到完美，可能并不是获得最高可靠性的最佳路径。

C++ 没有类型安全，你可以把它弄崩。他的回应很干脆：任何跑在计算机上的东西我都能弄崩。我要真想进你的机器，我大概会去试 SQL 注入，而不是去破你的类型系统。

## 识别丑代码比识别美代码容易

怎么让代码变可靠？他的答案只有一个词：简化。

不是先上测试框架，也不是先上运行时检查。第一步是让代码变少，让出错的概率变低。他引了爱因斯坦那句老话：尽可能简单，但不能更简单。

具体怎么做？他给了一个判断标准。如果你思考问题的方式没有体现在代码里，那代码里就缺了一块，那一块只存在于你脑子里。看代码的人能看到它做什么，看不到你想什么。

当你能把想法直接表达出来，代码就变得可维护、易找错、易修改，也更好测试。**顺便，它跑得更快。**于是你需要更少的机器，可能出故障的硬件也就更少。

至于怎么判断一份代码是不是干净的，Fridman 问得很直接：假设把福特 F-150 的代码给你，你能看出来这是不是一团乱麻？

答案是有经验的开发者能闻出来。

> 识别丑比识别美容易。原因是美有时候来自创新和不寻常，你得想一会儿才能领会。而混乱有很多共同点。（斯特劳斯特卢普）

他这些年一直在把"好代码长什么样"写成规则，目前这一版叫 C++ 核心准则（C++ Core Guidelines）。他的表述很克制：规则本身造就不了好程序员，但它限制了损害的范围，减少了犯错的可能性。

他用了一个很漂亮的类比。把所有雕刻的规则写进大理石，也变不出米开朗基罗。写一个好程序，除了手艺，还需要一点灵感、理解和天赋，而灵感没法监管。你能规定的只有手艺那一层。

## 静态分析真正的作用是教育

他很看好静态分析，理由在于它能抓"用法"，抓 bug 只是附带。

他举的例子是资源泄漏。在 C 那一层，你有一个 malloc，就必须有一个配对的 free。如果两个都在同一个函数里，分析起来很容易，看到一个 malloc，就该在附近找到一个 free。但如果中间隔着一堆代码，指针被传出函数，free 在别的地方发生，问题立刻变成几乎不可解。

静态分析跑一遍程序，会找到一些泄漏，也会找到大量它分析不下去的地方，因为结果依赖运行时，或者依赖分析器够不够聪明，或者干脆跑不完。

一旦你把静态分析和一套使用规则结合起来，你就能看出规则为什么被违反。你不需要解决全部问题，你需要的是别掉进那个无底洞。

他对静态分析的评价很高：它像一个教学工具，在你写未来代码的时候给你指路。

更深一层的原因是他对错误处理代码的悲观。代码一旦跑起来才报错，你就必须写错误处理器。错误处理代码是最难写的代码之一，因为出问题的时候，你往往并不确切知道出了什么问题。你不知道问题是什么，你凭什么恢复？

所以他宁愿在代码跑起来之前就把错误找出来。

## 抽象不该比手写慢

这里到了整场对话的技术核心，零开销原则。

> 如果你有一个抽象，它相对于等价的低层代码，不应该带来任何额外成本。（斯特劳斯特卢普）

举矩阵乘法。用矩阵这个抽象写出来的乘法，应该快到让你没法通过退回数组和指针再快一点。

实际上有人写出来了，而且比 Fortran 快。原因很反直觉：一旦你有了正确的抽象，编译器就能消除临时对象，做循环融合这类优化。这些事手工做极其痛苦，在低层语言里几乎做不好。

这个故事有个流传很广的后续。八十年代，他的朋友 Doug McIlroy 在演讲后问了一句：如果我把你这段 C++ 改写成 C，会快多少？答案是会慢很多。

他特别澄清了一点：他从来没说过 C++ 是面向对象编程语言。这句话被引用了无数次，但原话不长这样。

> 我说的是 C++ 支持面向对象编程，也支持其他技术。（斯特劳斯特卢普）

这个区别有实际后果。复杂而有趣的问题，最好的解法通常要同时用到面向对象、数据抽象、函数式，以及传统 C 风格代码。一个只允许一种范式的语言，会在某个环节逼你绕路。

他在设计 C++ 的时候很早就明白一件事：不能只是往语言里加特性。看到什么好看就加，听谁要什么就加，一个个加进去，最后得不到一个协调的整体。你需要一组原则来决定什么该进、什么不该进、一个特性要改到什么程度才能进。

这些原则里大部分不是语言技术问题。比如"不要破坏静态类型系统"，理由很朴素：他要东西在合理的硬件上可靠地跑。

## 编译器的性能从哪里来

零开销原则靠什么实现？三样东西同时到位：编程技术、语言特性、实现技术。

他提到 Brian Kernighan 说过的一句话，C++ 能成功，部分原因是他早期编译器里下的功夫。他自己写了不少用这套东西的代码。

一个人不可能同时精通所有领域。他举了并发编程的例子：你需要懂并发算法，需要懂无锁编程的细节，需要懂编译器技术，还要懂应用领域，比如某些图形学或者 Web 服务器那类负载。这些东西塞不进一个脑袋，但一个两三个人的小团队可以做到。

## 四种编译器，和他讨厌的那个词

为什么 C++ 有很多种实现？没人做过这个决策，它从一开始就是既成事实。

他设计 C++ 的时候，世界不是一台 x86 加 Linux。他想的是要利用各种已有的后端基础设施。然后他发现用户在用二十五种不同的链接器。他可以写一个自己的链接器，但他不可能写二十五个，同时还推进语言本身。

所以多种编译器是从一开始就存在的前提。今天至少有四个前端：Clang、GCC、微软、EDG。EDG 供应了大量独立组织和嵌入式行业。后端则多得没法数，嵌入式世界的芯片架构差得太远，单一实现从来就不是选项。

他顺手说了一句：**他讨厌单一文化。**

单一文化的危险在于，拥有它的人会僵化，没有竞争，没有创新动力，反而有大量动力去给变化设障碍，因为这个世界对他们太舒服了。GCC 曾经很好，后来有点僵，Clang 出现之后微软也变好了很多。少数几个前端的存在，给标准符合性、性能、错误信息质量、编译速度都施加了压力。

## 构造函数和析构函数

问到他个人最喜欢的 C++ 特性，答案很基础：构造函数和析构函数。

构造函数为一个对象建立好使用环境，析构函数在结束时清理掉所有烂摊子。**这是 C++ 的关键，是它不必依赖垃圾回收的原因，是它能给出可预测性能的原因。**

这个想法有个更广为人知的名字：RAII，资源获取即初始化。他的自评是，这是他为什么不该去做广告的例子。这么好的一个想法，被他起了这么个名字。

时间点也很早。1979 年，他开始做那个当时叫"带类的 C"的东西，大概第二周，构造和析构就进去了。

逻辑是一步步推出来的。你控制了对象的出生和死亡，就必须控制拷贝，因为拷贝是另一种创建对象的方式。控制完拷贝，你还得能把对象搬来搬去，于是有了移动语义。这组操作定义了一个 C++ 类型能用什么方式存在。

Fridman 把这件事抬到了哲学层面：创建一个类型的实例、释放它的资源，就像出生和死亡定义了一个人的生命。

斯特劳斯特卢普接了这句话，并顺势说，哲学很重要。**没有哲学就做不好语言设计，因为你决定的其实是人们能表达什么、怎么表达。**

## 概念为什么拖了三十年

模板是 C++ 泛型编程的基础。编译器看到模板和参数，把两者结合，生成一段代码，效果等同于你专门为那个类型手写了一份。信息拿得更全，所以有时生成的代码比人写的还快。

代价是调试。优化后的代码从来就不好读。1983 年那个 C++ 前端就已经做了前端和后端两层优化，生成的 C 代码是给机器看的，不是给人看的。加上模板之后更糟，因为优化器会把代码不同部分的信息拖到一起。

实际做法就是关掉优化器调试，先把逻辑层面搞对。

真正难的部分在概念（concepts）。

1987 年他做模板的时候，想要三样东西：极度灵活，能表达他想象不到的东西；和手写代码一样快或更快；能表达模板对参数的要求，也就是接口约束。

前两个他做到了，第三个困扰了他二十多年。函数参数的类型检查是他推动进入 C 的，他很清楚好接口的价值。但模板的接口约束，他和当时所有人都不知道怎么同时满足这三点。

> 我必须有这个工具，否则它就不算 C++。（斯特劳斯特卢普）

2003 年前后，Gabriel Dos Reis 开始系统分析这个问题，印地安那大学的一个老朋友也启动了项目。他们以为两三年能搞定，那样 C++11 就会在 2006 或 2007 年发布。

结果核心思路就是错的。

> 我们太因循了。它不太贴合 C++。它对隐式转换的支持不好，对混合类型的算术运算支持不好。很多东西来自函数式社区，而那个社区处理多类型的方式跟 C++ 不一样，对能表达什么有更多限制，也没有那么严苛的性能要求。（斯特劳斯特卢普）

他们试得很苦，也取得了一些成果，但最后编译不够快、用起来太难、运行不够快，除非优化器达到当时还不存在的水平，而那个水平今天也还没到。

最后落地的方案是另一条路：一组参数定义一组操作，通过一张交互表来查找，思路类似虚函数表，然后再想办法优化掉这层间接。这个概念在 C++20 里，2019 年已经在 GCC 和 Clang 里可用好几年，微软即将跟上，标准库也已经在用。

概念本质上就是编译期谓词。你能问一个类型：你是序列吗？你有 begin 和 end 吗？你是随机访问序列吗？你有下标吗？你的元素类型支持小于号吗？

以前模板说的是"我接受任何类型"，现在它能说"我接受满足这些条件的类型"。

这个词是 Alex Stepanov 起的，C++ 泛型编程之父。他的理由很直白：这些都是一个领域里的基本概念，就该叫概念。

## 一年开三次会，一个组织一票

标准化的起源很有意思。八十年代初，IBM 和 HP 各来了一个人，坐进他办公室，说要标准化 C++。

他觉得莫名其妙：这语言还没做完，没到能正式标准化的程度。

对方的回答是：你不明白。我们的组织依赖 C++，我们不能依赖一个属于别家公司的东西，那家公司可能是我们的竞争对手。我们当然可以信任你，但你可能被公交车撞了。

后面还有半句更关键的：你最好参与进来，否则我们就自己搞，而我们知道你做得更好。

连哄带劝，1989 年底在华盛顿开了第一次会，二十五个人的规模，据说创了这类会议的记录。会上先给大家讲 ANCI 的规则。

这套流程完全开放：交一笔会费就能参加，当年不到一千美元，现在大约一百八十美元。一年开三次会，每次一周，技术讨论，然后投票。**投票是一个组织一票，所以 IBM 带十个人来也压不住场面。**

他对比了一句：这比让他一个人决定要好，也比让 AT&T 这样的单一组织决定要好。标准化很不愉快，很像民主。而民主，按丘吉尔的说法，是最坏的制度，除了其他所有制度以外。

1990 年第一次技术会议，1998 年发布第一个标准。当时他们想，这次学会了，下一个六年就能出来。

结果花了十三年。

原因是第二系统效应：既然已经知道怎么做了，那就做得更好一点吧，于是野心膨胀，时间拉长。还有一个规律，越是临近发布，越有人冒出一个绝妙的主意，非加不可。

C++11 那次他们赌对了，加进去的东西确实救了 C++。之后有人想复制这个成功，但没那么戏剧性，而且越拖越久。

解决办法很简单：发得更勤。十年周期里出现一次延期，你意识到的时候已经过去十一年了。三年周期里出现延期，三四年就能补回来。于是 14 准时，17 准时，20 也会准时。

这个可预测性对编译器实现者极其重要，因为他们有了明确目标，并且真的交付。他的原话是：C++11 之后，多数编译器花了两年才做到"够用"；14 的时候情况好了很多；17 的时候几乎所有厂商都在当年发货；而 20，因为大多数实现在 2019 年就已经提前交付，他有底气说这次也会准时。

## 语言设计是哲学问题

Fridman 问他，有没有可能未来出现一套统一的语言设计原则，就像物理学追求统一理论那样。

斯特劳斯特卢普把两边的年龄摆了出来。现代物理从伽利略算起，七百年。现代计算从 1949 年前后算起，七十年。差了十倍。而且物理学不用操心"用户"这件事，语言设计得操心，因为写程序的是人。

所以他觉得这个领域非常不成熟。但在哲学层面，确实存在可以达成共识的原则：别泄漏资源，别在运行时处理你本不必处理的错误，别破坏你自己定下的类型系统。类型系统可以有很多种，但一旦选定了一种，就不要打破它。

他也看到了实际的收敛。C++ 早年采纳的 RAII，二十年后在垃圾回收语言里以 disposal pattern 之类的形式出现，那些语言也在努力不要事事依赖 GC。

他讲了一段很有意思的往事。有一次他和 Common Lisp 的几位设计者坐在一起聊语言和语言特性。一开始什么都没谈成，彼此看不顺眼，他甚至开玩笑说自己不喜欢那些括号。聊着聊着突然通了：他描述自己遇到的某个问题，以及他是按什么原则解决的；对方说他们遇到过另一个问题，也是按同样的原则解决的。他们一起走过了 C++ 的大块内容和 Common Lisp 的大块内容，发现两边的推理方式、底层原则其实高度相似。

不同的是约束条件和目标用户。

**原则可以共享，取舍不能。**这是他对"语言统一"这个问题最诚实的回答。

## 84% 的准确率，和那剩下的部分

Fridman 把话题引向机器学习。他的类比是：写程序是造一个接受输入、产生输出的东西；机器学习是在数据上训练出这么一个东西。区别在于后者是模糊的、有噪声的，像人一样。

斯特劳斯特卢普的回答毫不含糊：那是另一个世界。

> 我不喜欢模糊。人们说希望人人都能编程。我不想人人都来编我的飞机控制器和汽车控制系统。我希望那是工程师做的，是专门受过教育、专门被训练来做这件事的人做的。（斯特劳斯特卢普）

他把 C++ 的定位说得同样直白：这门语言服务的是专业人士，是一把锋利有效的工具，交给那些追求精确的人。

你不会让不懂数学的人去做计算。掰手指头是送不上月球的。

然后他给出了一个具体的数字判断。Fridman 提到 99.8% 的准确率，他的回应是：他看到的更多是 84%，而且要靠大量血汗才能推到 92.5%。

84% 在你做预筛选、把结果交给人类复核的场景里完全够用，甚至比人做得好。但它在涉及生命的场景里不够。**这个数字划出的是适用边界，跟技术本身好不好没有关系。**

他对自动驾驶的担忧落在一个非常具体的地方。他听说过一种设计：当 AI 系统遇到处理不了的情况，就把控制权交还给人类。而那个人可能正在看书，可能正在睡觉，他被叫醒后有三十秒，或者只有三秒，要搞清楚 AI 没搞定什么，然后做对。

> 这很吓人。人和机器之间的交接成本，怎么算？（斯特劳斯特卢普）

他说完又补了一句：这个问题被摆出来了，还谈不上无解。他自己的偏好是干脆别依赖人。开核反应堆也好，开自动驾驶也好，最好是设计一个永远不需要向人求助的系统。

这句话从一个造了四十年可靠系统的人嘴里说出来，分量不一样。AI 可不可靠是另一回事。一个要求人随时待命的系统，等于把两种性质完全不同的不可靠叠在了一起。

他也承认这些系统就架在 C++ 之上。这也是他必须持续关注那个领域的原因，尽管他明确说自己永远不会成为那方面的专家。这又回到他反复强调的那件事：今天没有哪个大系统是用一种语言写的，而且理由充分。不同领域需要不同工具、不同原则，然后它们互相接触。

## 四十年里最让他骄傲的，是望远镜和火星车

Fridman 问他，回头看这辈子的工作，哪一刻让他觉得"我干得不错"。

答案没有落在任何一个语言特性上。C++ 是几个好想法、大量苦工、一点运气的组合。他有几次想离开，但总被拽回来。一半是因为他在这个领域最有效率，另一半是因为在 C++ 的上下文里做事，影响面大得多。

> 如果我明天做对了什么，有四五百万人会捡起来用。如果我去别的领域，我得先学，然后得把它建起来，然后还得看有没有人愿意用。（斯特劳斯特卢普）

真正让他撑下来的，是能看到人们拿它做出了什么。

他去看过莫纳克亚山上的望远镜。他去看过福特怎么造车。他去过 JPL，看过火星车是怎么做出来的。他说了句很朴素的话：这么多酷东西在发生，而大部分酷东西是相当不错的人做出来的，有时候还在相当不错的地方，剑桥、索菲亚·安提波利斯、硅谷。

代码是中心，但不止是代码。

## 这场对话真正在讲什么

把它当成一场关于 C++ 的访谈很容易，但里面那些判断的适用范围远大于一门语言。

他反复回到同一个结构：先确定约束，再谈方案。他的约束是性能、可靠性、可部署性；他的结论是抽象必须免费，标准必须准时，错误必须在运行前抓住。所有具体的语言特性，都是从这个约束推导出来的结果，没有人先喜欢上某个特性再回头找理由。

他对简化有一段话值得单独记住。**如果代码里没有体现你对问题的思考方式，那么你的思考就只存在于你脑子里，代码看不见它。**而看不见的东西没法维护、没法测、没法改。他后面那句更妙：当你能直接表达想法时，代码顺便也跑得更快了。

还有一层常被忽略的判断：安全、性能、保密都是系统属性。单点做到完美，不等于系统可靠。这个视角对今天做 AI 系统的人尤其刺人，因为整个行业的叙事都集中在模型这一层。

最后是他对"什么不该做"的坦率。他讨厌单一文化。他承认 C++ 被用在比特币挖矿上，耗电量相当于瑞士，而且主要服务犯罪。他明确说不希望所有人都来编程。一个做了四十年工具的人，能清楚说出自己的工具不该用在哪，这种自觉比任何技术洞见都稀缺。

他在访谈最后被问到还有什么要说，只留了一句：会做得更好。

## 如果你想把这场对话变成行动

- 学一门和你日常工作范式完全相反的语言。你已经会 C++，去写半年 Haskell 或 Lisp；你只写 Python，去写一段真正需要手动管理内存的代码。第二门语言带来的收益远大于第三门。
- 下次性能不够时，先删代码，别先加优化。把那些"聪明的部分"拿掉，看是否反而更快。缓存和分支预测的惩罚比指令数更狠。
- 给你的模板或泛型接口加上约束。如果你在写 C++20，用概念；如果在写别的语言，用类型标注或接口声明。让"我接受任何类型"变成"我接受满足这些条件的类型"，报错信息会从一屏变成一行。
- 把资源管理和对象生命周期绑在一起。构造函数获取，析构函数释放，不要写手动清理路径。这条原则在任何有 RAII 或类似机制的语言里都成立。
- 在写第一行代码之前，先写下三条这个项目不可违反的原则，比如不破坏类型系统、不在运行时处理可预见的错误、不引入无法静态检查的隐式状态。原则要在特性之前定，否则你只是在堆功能。
- 做安全关键系统时，别把"AI 处理不了就交给人"当兜底方案。先算清楚人要多久才能理解现场，如果这个时间不够，那这个设计就是错的。
- 读一遍 C++ Core Guidelines。不一定用它写代码，用它训练自己闻出坏代码的能力。识别丑比识别美容易，而这项能力可以刻意练习。
