# 本賈尼·斯特勞斯特盧普：C++

> C++ 設計者談語言的設計取捨、零開銷抽象的理念，以及程式設計教育與好程式碼的標準。

- 原標題：Bjarne Stroustrup: C++
- 期數：特別節目
- 釋出日期：2019-11-07
- 嘉賓 / 主題：本賈尼·斯特勞斯特盧普
- 網頁版：https://lex.qiaomu.ai/tw/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。不一定用它寫程式碼，用它訓練自己聞出壞程式碼的能力。識別醜比識別美容易，而這項能力可以刻意練習。
