
“如果我們必須用對(duì)底層的絕對(duì)掌控來(lái)?yè)Q取物理極限的性能,那么 C++ 依然是這個(gè)星球上無(wú)可替代的語(yǔ)言。”
嘉賓| David Sankel 采訪 | 吳詠煒
責(zé)編|夢(mèng)依丹
出品 | CSDN(ID:CSDNnews)
在 Rust 強(qiáng)勢(shì)崛起、AI 編程重塑開(kāi)發(fā)范式的今天,C++ 這座歷經(jīng)四十載風(fēng)雨的編程大廈,似乎正面臨著前所未有的生存拷問(wèn)。
內(nèi)存安全漏洞是否真的無(wú)解?
AI 生成的代碼究竟是福音還是隱患?
當(dāng)“未定義行為”從優(yōu)化的基石變?yōu)榘踩膲?mèng)魘,C++ 標(biāo)準(zhǔn)委員會(huì)又將如何應(yīng)對(duì)?
帶著這些尖銳而深刻的問(wèn)題,在 2025 全球 C++ 及系統(tǒng)軟件技術(shù)大會(huì)的采訪間,奇點(diǎn)智能研究院首席技術(shù)咨詢(xún)師吳詠煒與 Adobe 首席科學(xué)家、C++ 標(biāo)準(zhǔn)委員會(huì)資深委員 David Sankel 展開(kāi)了一場(chǎng)直擊痛點(diǎn)的深度對(duì)話(huà)。
![]()
左:吳詠煒,右: David Sankel
如有興趣觀看完整視頻,可在文末獲取
David Sankel 沒(méi)有回避任何一個(gè)敏感話(huà)題。從揭示“新代碼比舊代碼更脆弱”的反直覺(jué)真相,到坦陳 C++ 在工具鏈生態(tài)上被 Rust“降級(jí)打擊”的無(wú)奈,再到對(duì) AI 編程助手“既依賴(lài)又懷疑”的矛盾心態(tài),Sankel 以一位頂尖語(yǔ)言設(shè)計(jì)者的視野,為我們抽絲剝繭,還原了一個(gè)真實(shí)、復(fù)雜且充滿(mǎn)生命力的 C++ 世界。
這不僅是一場(chǎng)關(guān)于技術(shù)的探討,更是一次關(guān)于如何在不確定的技術(shù)浪潮中尋找確定性的思想碰撞。
以下為對(duì)話(huà)全文:
吳詠煒:嗨 David,歡迎來(lái)全球 C++ 及系統(tǒng)軟件技術(shù)大會(huì)的采訪間。請(qǐng)你先向大家打個(gè)招呼。
David Sankel:大家好。真的很高興能來(lái)到這里,感覺(jué)特別棒。
吳詠煒:首先,我們來(lái)探討一下現(xiàn)代代碼與遺留系統(tǒng)的安全性問(wèn)題。你在本次大會(huì)演講中提到了一個(gè)耐人尋味的趨勢(shì):大多數(shù)內(nèi)存安全漏洞源于新編寫(xiě)的代碼,而不是遺留系統(tǒng)。 你認(rèn)為這是什么原因造成的?是因?yàn)檎Z(yǔ)言固有的復(fù)雜性、對(duì)現(xiàn)代特性的誤用、開(kāi)發(fā)者經(jīng)驗(yàn)不足,還是工程流程和工具鏈存在缺口?
David Sankel:這個(gè)現(xiàn)象的核心在于“代碼硬化”(Code Hardening)的過(guò)程,它通常只發(fā)生在那些長(zhǎng)期承受巨大安全審查壓力的舊代碼上。
以 Zlib 這個(gè)古老的 C 語(yǔ)言庫(kù)為例,多年來(lái),無(wú)數(shù)人都在積極地試圖攻破它。在這個(gè)過(guò)程中,絕大多數(shù)潛在的漏洞都已經(jīng)被挖掘并修復(fù)了。只要這種對(duì)抗性的壓力持續(xù)存在,代碼就會(huì)隨著時(shí)間的推移變得越來(lái)越堅(jiān)固。
漏洞出現(xiàn)在新代碼中的原因,實(shí)際上僅僅是因?yàn)檫@些代碼還沒(méi)有時(shí)間在那種對(duì)抗性壓力下經(jīng)過(guò)“歷練”。這完全是關(guān)于漏洞生存周期的問(wèn)題。如果你看看舊的 Zlib 代碼剛出來(lái)的時(shí)候,它也有成噸的漏洞,那時(shí)候的“遺留代碼”在當(dāng)時(shí)也是“新代碼”。這似乎只是公共領(lǐng)域軟件的一種現(xiàn)象,因?yàn)槿藗兛偸窃谠噲D攻擊它。
因此,這主要是一個(gè)成熟度的問(wèn)題:代碼越成熟,Bug 自然越少。
這種現(xiàn)象積極的一面是,我們不需要回頭去處理所有的代碼庫(kù)。如果你拿 Adobe Photoshop 來(lái)說(shuō),它有 6800 萬(wàn)行代碼,我們無(wú)法回頭去修復(fù)所有那些舊代碼。但好消息是,我們其實(shí)不必像防范新代碼那樣去焦慮舊代碼。我們將防御重點(diǎn)集中在新引入的代碼上,這讓內(nèi)存安全問(wèn)題從一個(gè)“不可能完成的任務(wù)”變成了一個(gè)“可控的工程問(wèn)題”。
吳詠煒:我們知道,在 C 語(yǔ)言中,由于開(kāi)發(fā)者通常需要直接管理定長(zhǎng)數(shù)組和原始內(nèi)存,緩沖區(qū)溢出這類(lèi)問(wèn)題非常普遍。理論上,C++ 引入了許多現(xiàn)代特性,本應(yīng)大幅降低此類(lèi)風(fēng)險(xiǎn)。但現(xiàn)實(shí)數(shù)據(jù)卻表明,我們依然面臨著大量的內(nèi)存相關(guān)漏洞。為什么在機(jī)制更完善的 C++ 中,這類(lèi)問(wèn)題依然無(wú)法根除?
David Sankel:C++ 確實(shí)通過(guò)引入高級(jí)抽象降低了內(nèi)存安全漏洞的發(fā)生頻率,但這并不意味著它從根本上消除了隱患。
現(xiàn)實(shí)情況是,工程師仍然很容易寫(xiě)出導(dǎo)致越界訪問(wèn)的代碼。過(guò)去是對(duì) C 風(fēng)格數(shù)組的越界,而現(xiàn)在的“現(xiàn)代版本”則是對(duì) std::vector 的越界訪問(wèn)——其本質(zhì)依然是相同的內(nèi)存安全問(wèn)題。 再比如使用未初始化的變量,這種風(fēng)險(xiǎn)在 C++ 中也并未消失。
歸根結(jié)底,C++ 繼承了 C 語(yǔ)言的底層內(nèi)存模型和許多“不安全”的基因。只要這些從 C 語(yǔ)言遺留下來(lái)的底層機(jī)制仍然被允許使用,或者現(xiàn)代容器的使用方式缺乏強(qiáng)制性的安全約束,內(nèi)存安全漏洞的溫床就依然存在。
吳詠煒: 相比十年前,我們現(xiàn)在擁有了強(qiáng)大得多的動(dòng)態(tài)分析工具。比如 Memory Sanitizer (MSan)、Address Sanitizer (ASan)、Thread Sanitizer (TSan) 以及 Undefined Behavior Sanitizer (UBSan) 等等
David Sankel:你說(shuō)得完全正確。問(wèn)題是:這些工具是否在 C++ 生態(tài)系統(tǒng)中被普遍使用了?遺憾的是,我認(rèn)為答案是否定的。
阻礙工具普及的原因可以分為兩類(lèi)。一類(lèi)是主觀因素——比如開(kāi)發(fā)者缺乏認(rèn)知,或者根本不在乎;但更關(guān)鍵的,是一類(lèi)非常現(xiàn)實(shí)的客觀門(mén)檻:這些工具的配置成本極高。
要想讓這套 Sanitizer 組合在構(gòu)建系統(tǒng)中完美運(yùn)行,需要付出巨大的工程代價(jià)。這往往要求你在項(xiàng)目啟動(dòng)之初就具備極高的前瞻性,并投入資源去配置基礎(chǔ)設(shè)施。但在項(xiàng)目早期,你甚至不知道它能不能存活下去,往往無(wú)暇顧及這些。
這就導(dǎo)致了一個(gè)典型的“成功悖論”:等到你的開(kāi)源庫(kù)大獲成功、被廣泛采用時(shí),它可能一直是在沒(méi)有 Sanitizer 保護(hù)的“裸奔”狀態(tài)下開(kāi)發(fā)的。突然之間,潛伏的漏洞隨著你的庫(kù)擴(kuò)散到了整個(gè)生態(tài)鏈。
更糟糕的是,即便你現(xiàn)在亡羊補(bǔ)牢加上了防護(hù),下游用戶(hù)依然可能在使用你的舊版本代碼。為什么?因?yàn)樵?C++ 生 態(tài)中,依賴(lài)管理和版本升級(jí)是一項(xiàng)昂貴的工程活動(dòng)。用戶(hù)往往因?yàn)樯?jí)成本過(guò)高而停留在有漏洞的舊版本上,導(dǎo)致問(wèn)題持續(xù)存在。
吳詠煒:但我認(rèn)為你的論點(diǎn)可能是我們不想用 C++ 寫(xiě)新代碼。但其實(shí),我們完全可以在新代碼中使用這些工具,而不是在舊代碼中,因?yàn)榕f代碼可能有更多的兼容性問(wèn)題。在新代碼中,我們絕對(duì)可以使用新工具。
David Sankel:你的論點(diǎn)建立在一個(gè)關(guān)鍵假設(shè)之上:即只要使用了這些新工具,就能解決所有、或者至少絕大部分的內(nèi)存安全漏洞。 誠(chéng)然,它們能大幅緩解問(wèn)題,但現(xiàn)實(shí)數(shù)據(jù)卻給我們潑了一盆冷水。
讓我們看看 Google 的數(shù)據(jù)。在 Android 系統(tǒng)開(kāi)發(fā)中,他們擁有世界頂級(jí)的工程師團(tuán)隊(duì),并且在 C++ 開(kāi)發(fā)流程中強(qiáng)制啟用了所有的 Sanitizer 和最佳實(shí)踐。即便武裝到了這種程度,他們依然持續(xù)發(fā)現(xiàn) C++ 代碼中的內(nèi)存漏洞。
更令人震驚的對(duì)比來(lái)自于他們引入 Rust 之后的數(shù)據(jù):在同樣的嚴(yán)苛標(biāo)準(zhǔn)下,C++ 代碼產(chǎn)生的內(nèi)存安全漏洞數(shù)量幾乎是 Rust 代碼的 1000 倍。
這是一個(gè)非常“硬”的數(shù)據(jù)。它揭示了一個(gè)殘酷的現(xiàn)實(shí):工具只能緩解癥狀,卻無(wú)法根治病灶。
如果單靠打開(kāi) Sanitizer 就能徹底解決問(wèn)題,那么 Google 根本不需要大費(fèi)周章去引入新語(yǔ)言。既然連擁有最強(qiáng)技術(shù)實(shí)力的 Google 都無(wú)法在 C++ 中徹底封堵這些漏洞,這本身就證明了這是一個(gè)極其艱深、甚至可能是目前范式下無(wú)解的難題。
再舉個(gè)身邊的例子,我團(tuán)隊(duì)里的 Sean Parent——他是公認(rèn)的 C++ 泰斗級(jí)人物——依然會(huì)踩進(jìn)內(nèi)存安全的坑里。有一次他在處理復(fù)雜的模板元編程時(shí),面對(duì)層層封裝的抽象,想要搞清楚一個(gè)深埋其中的 auto&& 到底推導(dǎo)出來(lái)的是一個(gè)右值引用還是一個(gè)指向局部變量的懸垂引用,簡(jiǎn)直難如登天。
吳詠煒:是的,我認(rèn)為抽象是一個(gè)大問(wèn)題,會(huì)讓測(cè)試 constexpr 函數(shù)變得很難……我認(rèn)為模板元編程還要更難。實(shí)際上,我最近也遇到了一個(gè)這樣的問(wèn)題,也是在元編程中。我實(shí)際上立即發(fā)現(xiàn)了問(wèn)題,因?yàn)槌绦虮赖袅恕5宄?wèn)題到底在哪真的很難,因?yàn)閱?wèn)題隱藏得很深,而且僅在某些特殊場(chǎng)景里才出現(xiàn)。
David Sankel:對(duì),他的情況也是一模一樣的。
吳詠煒: 好的,讓我們轉(zhuǎn)向下一個(gè)關(guān)于 C++ 價(jià)值主張的問(wèn)題。如今 Rust 憑借“內(nèi)存安全”特性迅速崛起,Python 在 AI 時(shí)代更是占據(jù)主導(dǎo),也確實(shí)吸走了一部分原本依賴(lài) C++ 的用戶(hù)。但在游戲引擎、系統(tǒng)底層、高性能計(jì)算等核心場(chǎng)景,C++ 依舊穩(wěn)固。在你看來(lái),C++ 最核心、最不可替代的優(yōu)勢(shì)是什么?為什么這些優(yōu)勢(shì)至今仍難被其他語(yǔ)言取代?
David Sankel:我認(rèn)為 C++ 擁有一個(gè)任何人都奪不走的“利基市場(chǎng)”(Niche),其核心價(jià)值主張?jiān)谟冢核试S開(kāi)發(fā)者通過(guò)承擔(dān)“未定義行為”(Undefined Behavior)的風(fēng)險(xiǎn),來(lái)?yè)Q取絕對(duì)極致的性能。
讓我用一個(gè)最近看到的對(duì)比案例來(lái)說(shuō)明。有一段 C++ 代碼執(zhí)行某種整數(shù)運(yùn)算,這其中可能隱含著溢出或除以零的風(fēng)險(xiǎn)。但在編譯器的優(yōu)化下,這段代碼被極致精簡(jiǎn)為一條匯編指令:一個(gè)移動(dòng)加一個(gè)加法。
代價(jià)是: 如果輸入數(shù)據(jù)錯(cuò)誤,程序行為完全不可控(未定義)。
收益是: 如果你能保證數(shù)據(jù)正確,它就是物理上能達(dá)到的最快速度。
當(dāng)開(kāi)發(fā)者試圖在 Rust 中復(fù)刻這段代碼時(shí),困難出現(xiàn)了。Rust 的安全機(jī)制強(qiáng)制要求檢查“除以零”和“整數(shù)溢出 panic”。為了讓 Rust 代碼達(dá)到和 C++ 一樣的指令級(jí)效率,開(kāi)發(fā)者不得不使用大量的 unsafe 塊、特殊的編譯器提示(Hint)和注解。最終,性能確實(shí)追平了,但代碼量膨脹了四倍,且可讀性大打折扣。
這正是 C++ 的生存空間所在——當(dāng)你愿意接受這種激進(jìn)的權(quán)衡時(shí):
如果你在搞高頻交易(HFT),那么程序因?yàn)闃O小概率的錯(cuò)誤數(shù)據(jù)崩潰了,也許可以接受;但如果為了安全檢查拖慢了每一筆交易的速度,那就是不可接受的。開(kāi)發(fā)者只要最純粹、最快的機(jī)器碼,任何額外的安全檢查都被視為累贅;
同樣在游戲開(kāi)發(fā)方面,游戲如果出現(xiàn)了一個(gè)渲染錯(cuò)誤,或者像素偏了一點(diǎn),甚至偶爾崩潰重啟,玩家也許能忍受。但如果為了代碼安全導(dǎo)致幀率下降、開(kāi)發(fā)效率變慢(因?yàn)橐獙?xiě)繁瑣的安全注解),那是開(kāi)發(fā)商無(wú)法接受的。
除了這種對(duì)性能的極致追求,C++ 另一大支柱是歷史慣性。
以科學(xué)計(jì)算領(lǐng)域?yàn)槔珻++ 的地位并不完全因?yàn)樗Z(yǔ)言設(shè)計(jì)得多好,而是因?yàn)槟抢镆呀?jīng)沉淀了海量的成熟代碼。這就像 Fortran 一樣——至今像 LAPACK 這樣的 Fortran 庫(kù)仍是數(shù)值計(jì)算的基石。它們經(jīng)過(guò)了數(shù)十年的優(yōu)化,極其穩(wěn)定高效,沒(méi)有任何商業(yè)理由去重寫(xiě)它們。
C++ 也是如此。只要這些龐大的遺留代碼庫(kù)(Legacy Codebase)還在運(yùn)行,只要沒(méi)人愿意支付天文數(shù)字般的重寫(xiě)成本,C++ 就將繼續(xù)作為這些領(lǐng)域的中流砥柱存在下去。
吳詠煒:這引出了一個(gè)關(guān)于開(kāi)發(fā)生產(chǎn)力(Productivity)的有趣悖論。剛才你提到,為了在 Rust 中追求極致性能(對(duì)齊 C++ 的匯編級(jí)優(yōu)化),代碼量可能會(huì)膨脹四倍,這意味著生產(chǎn)力大幅下降。但另一方面,業(yè)界許多報(bào)告又聲稱(chēng) Rust 程序員的生產(chǎn)力顯著高于 C++。
這兩個(gè)截然相反的結(jié)論同時(shí)存在,是否存在矛盾?也許,這是因?yàn)樗鼈儜?yīng)用于不同的領(lǐng)域(domain)?
David Sankel:這絕對(duì)是領(lǐng)域決定的,不存在矛盾。關(guān)鍵在于你是否在順應(yīng)語(yǔ)言的設(shè)計(jì)哲學(xué)。
如果你試圖逆著 Rust 的性子來(lái)——比如非要像寫(xiě) C++ 那樣去寫(xiě)充斥著裸指針和極致微操的“不安全代碼”——那么是的,你會(huì)痛苦萬(wàn)分,生產(chǎn)力會(huì)暴跌。
但如果你順勢(shì)而為,利用 Rust 擅長(zhǎng)的領(lǐng)域——比如進(jìn)行高層邏輯組裝、編寫(xiě)默認(rèn)安全的業(yè)務(wù)代碼,或者通過(guò)安全的接口調(diào)用底層高性能庫(kù)——你會(huì)感受到前所未有的生產(chǎn)力飛躍。
讓我舉一個(gè)讓我深受震撼的親身經(jīng)歷:
有一次我在寫(xiě) Rust 項(xiàng)目,突然覺(jué)得如果能嵌入一個(gè) JavaScript 解釋器會(huì)很棒。在 Rust 里我是怎么做的?我只需要在 Cargo.toml 配置文件里加了一行代碼,引入一個(gè)現(xiàn)成的 Crate(庫(kù))。幾秒鐘后,我就擁有了一個(gè)功能完備的 JS 解釋器。
試想一下,如果在 C++ 里做同樣的事,會(huì)是怎樣的噩夢(mèng)?
我要找一個(gè)合適的 C++ JS 引擎庫(kù)。
我要搞定它復(fù)雜的依賴(lài)項(xiàng)。
我要想辦法讓它的構(gòu)建系統(tǒng)兼容我自己的構(gòu)建系統(tǒng)。
我還要處理鏈接、頭文件路徑等一堆瑣事。
在 C++ 里,這是一個(gè)天文數(shù)字級(jí)的工作量;而在 Rust 里,只是“加一行配置”的事。
所以,Rust 所謂的生產(chǎn)力優(yōu)勢(shì),很大程度上并不在于語(yǔ)言語(yǔ)法本身,而在于其現(xiàn)代化的包管理生態(tài)系統(tǒng)。Cargo 對(duì)于 C++ 開(kāi)發(fā)者來(lái)說(shuō),簡(jiǎn)直是降維打擊般的體驗(yàn)提升。
吳詠煒:確實(shí),C++ 的痛點(diǎn)不僅僅在于沒(méi)有統(tǒng)一的包管理器,更深層的原因在于底層的二進(jìn)制不兼容性。我們有 GCC、Clang、MSVC 等不同的編譯器,它們各自有一套不兼容的名稱(chēng)修飾(Name Mangling)規(guī)則和調(diào)用約定(Calling Conventions)。這導(dǎo)致在 C++ 中分發(fā)預(yù)編譯庫(kù)(Pre-built Binaries)幾乎是不可能的任務(wù),每個(gè)人都必須從源碼重新編譯。
David Sankel:沒(méi)錯(cuò),編譯器生態(tài)的碎片化是一個(gè)巨大的阻礙。在 C++ 中,哪怕僅僅是“打包一個(gè)庫(kù)”這樣看似簡(jiǎn)單的動(dòng)作,都充滿(mǎn)了技術(shù)挑戰(zhàn)。
這里有一個(gè)非常深刻的對(duì)比。Rust(以及幾乎所有現(xiàn)代語(yǔ)言)從誕生之初就吸取了一個(gè)教訓(xùn):工具鏈必須是語(yǔ)言設(shè)計(jì)的一等公民。
C++ 只有語(yǔ)言本身(語(yǔ)法和標(biāo)準(zhǔn)庫(kù))被 ISO 標(biāo)準(zhǔn)化了。至于如何構(gòu)建、如何管理依賴(lài)、如何生成文檔……所有這些工具鏈層面的東西,標(biāo)準(zhǔn)委員會(huì)采取了“放任自流”的態(tài)度。
這種差異導(dǎo)致了結(jié)果的天壤之別。以文檔為例:
在 Rust 生態(tài)中,官方直接提供了 rustdoc。因此,整個(gè)社區(qū)只有一種文檔標(biāo)準(zhǔn),每個(gè)人都用同樣的方式編寫(xiě)注釋?zhuān)總€(gè)人都用同樣的工具生成頁(yè)面。這種同質(zhì)化(Homogeneity)帶來(lái)了極大的便利——對(duì)于任何一個(gè)第三方庫(kù),我閉著眼睛都知道去哪里找文檔,也知道文檔結(jié)構(gòu)長(zhǎng)什么樣。而在 C++ 中,這完全是混亂的。
吳詠煒:但我并不認(rèn)為在 C++ 現(xiàn)有的體系下這具有可行性。坦白說(shuō),我甚至反感由 ISO 這樣的機(jī)構(gòu)去強(qiáng)行標(biāo)準(zhǔn)化工具鏈或文檔工具。在我看來(lái),這根本就是不可能完成的任務(wù)。
David Sankel:問(wèn)題的關(guān)鍵其實(shí)不在于組織是否“正式”,而在于產(chǎn)出物的性質(zhì)。ISO 標(biāo)準(zhǔn)化流程的核心職能非常單一:發(fā)布規(guī)格說(shuō)明書(shū)(Specification)。僅此而已。
反觀 Rust 的組織方式,它完全是另一種范式。Rust 不僅僅發(fā)布類(lèi)似規(guī)格的 Rust Reference,它更核心的產(chǎn)出是軟件成品。所有這些軟件與文檔的集合體,才構(gòu)成了我們認(rèn)知中的“Rust”。它不僅僅是一紙標(biāo)準(zhǔn),而是一個(gè)完整的產(chǎn)品交付。
這就是兩者最根本的區(qū)別。ISO 的設(shè)立初衷就不是為了開(kāi)發(fā)和維護(hù)軟件產(chǎn)品。如果我們?cè)噲D強(qiáng)行通過(guò) ISO 流程來(lái)構(gòu)建一套統(tǒng)一的 C++ 工具鏈,結(jié)果注定會(huì)是一場(chǎng)災(zāi)難。這不僅違背了 ISO 的基因,在實(shí)際操作層面上也完全不可行。
吳詠煒:另一件事是,C++ 的模板特化(Template Specialization),它讓 C++ 在某種程度上完美契合了“開(kāi)閉原則”(Open-Closed Principle):你可以在完全不修改現(xiàn)有通用模板代碼的前提下,為特定類(lèi)型提供擴(kuò)展實(shí)現(xiàn)。
然而,Rust 似乎并沒(méi)有這種全功能的特化機(jī)制,卻依然發(fā)展得很好。這是否意味著,特化這個(gè)優(yōu)勢(shì)其實(shí)并沒(méi)有顯現(xiàn)出來(lái)?還是說(shuō) Rust 有其他的替代方案?
David Sankel:這一點(diǎn)非常有意思。當(dāng) Sean Parent 和我的團(tuán)隊(duì)開(kāi)始集體學(xué)習(xí) Rust 時(shí),他直接切入了最硬核的元編程部分。
幾乎是立刻,他就指出了這個(gè)痛點(diǎn):“Rust 沒(méi)有特化。如果沒(méi)有特化,你就無(wú)法進(jìn)行真正的泛型編程。” 這對(duì)習(xí)慣了 C++ 強(qiáng)大元編程能力的專(zhuān)家來(lái)說(shuō),確實(shí)是一個(gè)巨大的沖擊。
吳詠煒:這就是我不喜歡 Rust 的地方。所以我想聽(tīng)聽(tīng)你的看法。也許那真的沒(méi)那么重要?或者怎么說(shuō)?
David Sankel:我必須承認(rèn),與 C++ 相比,這確實(shí)是 Rust 的一個(gè)顯著短板。不僅沒(méi)有特化,Rust 目前也缺乏可變參數(shù)模板。這就導(dǎo)致你經(jīng)常需要用笨辦法繞路——比如為了支持不同數(shù)量的參數(shù),你得手動(dòng)把一個(gè)函數(shù)復(fù)制粘貼寫(xiě)很多個(gè)版本。
這種感覺(jué)讓我恍惚間回到了原始的 C++98 時(shí)代。但這并非設(shè)計(jì)者的疏忽,而是深層機(jī)制權(quán)衡的結(jié)果。Rust 引入了嚴(yán)格的借用檢查器,并且采用了受檢泛型(Checked Generics)模型。
在 C++ 中,即便你定義了 Concept,如果你在模板函數(shù)里偷偷用了一個(gè) Concept 沒(méi)聲明的操作,只要實(shí)例化時(shí)的具體類(lèi)型支持這個(gè)操作,C++ 編譯器通常也就睜一只眼閉一只眼放行了。
在 Rust 中(受檢泛型),編譯器極其嚴(yán)格。它強(qiáng)制要求泛型函數(shù)內(nèi)部只能使用 Trait(對(duì)應(yīng) C++ 的 Concept)中顯式聲明的接口。這雖然帶來(lái)了極佳的接口契約保證,但也使得實(shí)現(xiàn)“特化”和“可變參數(shù)”在理論上變得異常困難。
目前,Rust 社區(qū)雖然有一些關(guān)于如何實(shí)現(xiàn)這些特性的構(gòu)想,但尚未落地,這仍是一個(gè)未解的難題。
所以歸根結(jié)底,這就是一種取舍問(wèn)題,你想要受檢泛型帶來(lái)的類(lèi)型安全和清晰契約,就不得不暫時(shí)忍受特化能力的缺失。你得自己權(quán)衡這種交換是否劃算。
吳詠煒:那么在你和 Sean 的討論中,結(jié)論是什么?這個(gè)特性對(duì) Adobe 或你的項(xiàng)目真的很重要嗎?從理論角度來(lái)看,要想在一種語(yǔ)言中完全實(shí)現(xiàn) Stepanov風(fēng)格的泛型編程,你真的需要那種特化。我實(shí)際上只是希望我的代碼在不修改現(xiàn)有代碼的情況下可擴(kuò)展。所以我想要符合開(kāi)閉原則。
David Sankel:我認(rèn)為你在 Rust 里也能得到開(kāi)閉原則。你可以先定義一個(gè) Trait,聲明需要哪些函數(shù), 然后再為 Trait 提供一個(gè)通用的默認(rèn)實(shí)現(xiàn)。當(dāng)一個(gè)新類(lèi)型想要使用這個(gè)功能時(shí),它必須顯式地為自己實(shí)現(xiàn)這個(gè) Trait。
在 C++ 中,泛型函數(shù)(如 std::sort)是“即插 即用”的:只要你的類(lèi)型滿(mǎn)足 Concept(或隱式接口)的要求,編譯器就會(huì)自動(dòng)選用通用實(shí)現(xiàn)。而如果你需要更優(yōu)的路徑,還可以通過(guò)模板特化提供定制版本——整個(gè)過(guò)程無(wú)需修改原始泛型代碼,也無(wú)需顯式注冊(cè)。
但在 Rust 中,這兩種能力無(wú)法共存。你要么顯示地選擇加入,然后隨心所欲的進(jìn)行特化,要不你有一個(gè)自動(dòng)實(shí)現(xiàn),但不能特化它。
吳詠煒:好的,所以我們有辦法,但是是一種非常不同的方式。
David Sankel:是的,完全正確。C++ 中的 Concept,如果你的語(yǔ)法恰好符合 Concept 的要求,你就支持該 Concept。在 Rust 中,你必須顯式地說(shuō)你支持一個(gè) Trait(這相當(dāng)于 Concept),并說(shuō):“好的,這個(gè)特定的類(lèi)型或這組類(lèi)型支持這個(gè) Trait,這是它所需的函數(shù)的實(shí)現(xiàn)。” 所以它是選擇加入(opt-in)的語(yǔ)法。
吳詠煒:好的,下一個(gè)問(wèn)題是關(guān)于 AI 代碼的。隨著 AI 編碼助手的興起,許多開(kāi)源社區(qū)正在禁止 AI 生成的貢獻(xiàn)。作為標(biāo)準(zhǔn)委員會(huì)的一員,你對(duì)此有何看法?委員會(huì)有沒(méi)有收到或接受過(guò)由 AI 生成的提案或措辭?你有親自在 C++ 開(kāi)發(fā)中用過(guò)過(guò) AI 工具嗎?如果有,體驗(yàn)如何?
David Sankel:關(guān)于 C++ 標(biāo)準(zhǔn),確實(shí)有過(guò)由 AI 編寫(xiě)的提案,而且非常明顯,也非常令人討厭。那樣寫(xiě)的提案沒(méi)有任何進(jìn)展。當(dāng)然,這些是我們知道的。也許有人用 AI 寫(xiě)了一個(gè),而且寫(xiě)得太好了以至于我們沒(méi)有注意到。但我還沒(méi)有真正看到過(guò)這種情況。
我認(rèn)為開(kāi)源社區(qū)保護(hù)自己免受 AI 生成代碼貢獻(xiàn)的影響是有道理的。因?yàn)?AI 寫(xiě)出的一段代碼只是完成了一半。另一半是逐行仔細(xì)審查,確保它實(shí)際上是正確的,并能完成所有需要做的事情。
所以當(dāng)你有一個(gè)開(kāi)源項(xiàng)目,現(xiàn)在任何人都可以生成做某事的 Pull Request,這意味著該庫(kù)的維護(hù)者必須投入大量的精力,來(lái)應(yīng)對(duì)這些貢獻(xiàn)者投入的零精力。這里需要某種制衡。也許有人必須證明他們值得信任,并確認(rèn)一個(gè)真正的人類(lèi)已經(jīng)花時(shí)間檢查了這個(gè)東西。
我確實(shí)有用過(guò) AI 生成代碼。以我的經(jīng)驗(yàn)而言,AI 產(chǎn)生的錯(cuò)誤足以讓我無(wú)法信任它生成的任何東西,除非我親自檢查。 任何將要發(fā)布或長(zhǎng)期使用的東西,我都必須非常非常小心。
它基本上將我寫(xiě)代碼的精力從“編寫(xiě)代碼并迭代”轉(zhuǎn)變?yōu)椤癆I 生成代碼,我仔細(xì)審查”。這感覺(jué)不太好。你知道,相比于審查代碼,我更喜歡寫(xiě)代碼,尤其是當(dāng)我審查 AI 的代碼而它在胡編亂造時(shí),有時(shí)候真的很讓我惱火。但總的來(lái)說(shuō),我認(rèn)為它在大多數(shù)情況下節(jié)省了時(shí)間。所以這可能是值得的。
AI 會(huì)變得更好嗎?有些人認(rèn)為它將成為最神奇的東西,你再也不用看代碼了。我不相信。我認(rèn)為對(duì)于目前我看到的任何技術(shù)和進(jìn)步,人類(lèi)都必須保持在循環(huán)中(Stay in the loop)。
吳詠煒: 具體來(lái)說(shuō),你在 C++ 和 Rust 代碼上使用 AI 工具的體驗(yàn)如何?
David Sankel:對(duì)于 C++:AI 傾向于生成更不安全的代碼。
學(xué)術(shù)研究數(shù)據(jù)表明,AI 生成的 C++ 代碼在客觀上比人類(lèi)編寫(xiě)的代碼更差,尤其是在內(nèi)存安全漏洞方面。
更令人擔(dān)憂(yōu)的是一種心理學(xué)現(xiàn)象:開(kāi)發(fā)者往往對(duì) AI 生成代碼的正確性過(guò)度自信,其信心程度甚至超過(guò)對(duì)自己親手編寫(xiě)代碼的信心。然而現(xiàn)實(shí)恰恰相反——AI 生成的代碼往往包含更多安全隱患。這是一個(gè)相當(dāng)令人不安的趨勢(shì)。
對(duì)于 Rust,當(dāng)涉及到內(nèi)存安全和 AI 生成的代碼時(shí),如果 AI 生成的代碼不安全,它就不會(huì)通過(guò)編譯。
吳詠煒:對(duì),它是強(qiáng)制性的。這就是區(qū)別。
David Sankel:目前 Rust 的語(yǔ)法和特性集比 C++ 小得多、也簡(jiǎn)單得多,這使得 AI 更容易生成語(yǔ)法正確、看似合理的代碼。當(dāng)然,這不意味著絕對(duì)可靠——我確實(shí)也見(jiàn)過(guò) Rust AI 產(chǎn)生一些非常瘋狂的“幻覺(jué)”。
總的來(lái)說(shuō),我認(rèn)為無(wú)論是 C++ 還是 Rust,現(xiàn)有的代碼語(yǔ)料庫(kù)都已足夠龐大,AI 能夠進(jìn)行有效的學(xué)習(xí)和代碼生成。
吳詠煒:我認(rèn)為至少作為一個(gè)輔助工具,AI 是非常有幫助的。順便說(shuō)一句,幾天前我想讓 AI 重構(gòu)我的一些 C 代碼(其實(shí)不是 C++),它識(shí)別出了一個(gè)潛伏了 10 多年的 Bug,因?yàn)樗鼜奈幢挥|發(fā)過(guò)。但 AI 注意到我在那里有個(gè)拼寫(xiě)錯(cuò)誤,把一個(gè)變量誤寫(xiě)成了另一個(gè)。它識(shí)別出來(lái)了。所以這非常有趣。
David Sankel:是的,我也遇到過(guò)這樣的時(shí)刻,它做了一些事情,你會(huì)想,“什么?它怎么……?太神了。”
吳詠煒:最后一個(gè)問(wèn)題。我想談?wù)勎炊x行為(UB)。UB 是大多數(shù)內(nèi)存安全問(wèn)題的根本原因。目前的標(biāo)準(zhǔn)流程中是否有積極的提案專(zhuān)門(mén)旨在減輕未定義行為或增強(qiáng)檢測(cè)?例如,通過(guò)更好的 Sanitizer 或編譯器診斷?
David Sankel:是的,一直有穩(wěn)定的提案流試圖解決未定義行為。我相信在 C++26 中,我們首次引入了“錯(cuò)誤行為”(Erroneous Behavior)這個(gè)概念。這使得一些以前未定義的事情現(xiàn)在有了完整的定義。
還有 Profiles(配置)也被提出過(guò),但這類(lèi)提案目前還非常不成熟,更像是一些初步構(gòu)想,缺乏任何實(shí)現(xiàn)經(jīng)驗(yàn)。正因如此,它未能進(jìn)入 C++26。
讓我有點(diǎn)擔(dān)心的是……最近很多關(guān)于未定義行為和解決內(nèi)存安全漏洞的提案確實(shí)是一些“異想天開(kāi)”的主意。你可以舉幾個(gè)例子說(shuō)“這是可以被檢測(cè)到的”,但它們?nèi)狈θ魏嗡惴ǎ挥谜f(shuō)規(guī)范或?qū)崿F(xiàn)了。我擔(dān)心這會(huì)分散我們的注意力。人們可能會(huì)說(shuō),“哦,這個(gè)問(wèn)題在未來(lái)某個(gè)時(shí)候會(huì)得到解決”,但實(shí)際上……那里并沒(méi)有實(shí)質(zhì)性的東西。
對(duì)我來(lái)說(shuō),目前最扎實(shí)、最有趣的努力,來(lái)自于 Timur Doumler 等人的一篇論文。他們沒(méi)有急于提出解決方案,而是做了一項(xiàng)極其重要的基礎(chǔ)工作:系統(tǒng)性地編目(Catalog)C++ 標(biāo)準(zhǔn)中每一個(gè)已知的 UB 實(shí)例,并對(duì)它們進(jìn)行分類(lèi)。
他們本質(zhì)上是在用一種科學(xué)的方法,為每一個(gè) UB 打上標(biāo)簽,然后問(wèn):“對(duì)于這一類(lèi) UB,我們到底能做些什么?”雖然他們目前還只是在編目階段,沒(méi)有提出具體的解決方案,但我認(rèn)為這才是正確的方向。它讓我們第一次有可能從宏觀上、系統(tǒng)性地去討論如何逐步消除 UB,而不是頭痛醫(yī)頭、腳痛醫(yī)腳。
吳詠煒:是的。我想在過(guò)去人們認(rèn)為未定義行為對(duì)優(yōu)化是一件好事。但現(xiàn)在,我認(rèn)為我們正在朝相反的方向發(fā)展。越來(lái)越多的人認(rèn)為未定義行為簡(jiǎn)直是邪惡的。我們想盡可能地消除它們,對(duì)吧?
David Sankel:完全正確。促成這一觀念轉(zhuǎn)變的關(guān)鍵因素之一,是 CPU 架構(gòu)的演進(jìn)。
讓我們以向量(Vector)的索引訪問(wèn)為例。如果你在訪問(wèn)時(shí)強(qiáng)制加上邊界檢。在過(guò)去,這可能會(huì)帶來(lái)巨大的性能懲罰,甚至讓執(zhí)行時(shí)間變成原來(lái)的四倍。而現(xiàn)在,得益于現(xiàn)代超標(biāo)量架構(gòu),配合指令預(yù)取和預(yù)執(zhí)行技術(shù),CPU 的流水線能力極強(qiáng)。
這意味著,很多以前昂貴的檢查操作,現(xiàn)在被現(xiàn)代硬件的并行能力“消化”了。實(shí)際上,你現(xiàn)在基本上可以“免費(fèi)”(Free)獲得這些安全檢查,而無(wú)需付出明顯的性能代價(jià)。
吳詠煒:是很多,但不是全部。因?yàn)槲掖_實(shí)遇到過(guò)一個(gè)使用 gsl::span 測(cè)試的案例。在這個(gè)案例中,使用 gsl::span 配合 std::copy 會(huì)使復(fù)制代碼慢 20 倍以上。所以如果我們只做一次性檢查,那是可以的。但如果我們不小心做了重復(fù)檢查,那代價(jià)會(huì)非常高昂 。
David Sankel:是的。這也是 Rust 生態(tài)系統(tǒng)中存在的問(wèn)題,因?yàn)樗麄兿胍浅8咝У拇a,但也想要安全。
如果你深入查看 Rust 標(biāo)準(zhǔn)庫(kù)的實(shí)現(xiàn),你會(huì)發(fā)現(xiàn)一種非常巧妙的模式:雖然代碼本質(zhì)上是“安全”的(意味著理論上每次訪問(wèn)都要檢查),但開(kāi)發(fā)者會(huì)在循環(huán)開(kāi)始前加入一條特定的前置斷言,比如“先檢查并確認(rèn)長(zhǎng)度小于某個(gè)值”。
為什么要這么做?因?yàn)榫幾g器(優(yōu)化器)看到這條前置檢查后,就能推斷出后續(xù)操作是安全的,從而在函數(shù)主體的循環(huán)中自動(dòng)消除(Elide)所有那些多余的重復(fù)檢查。
這就像是開(kāi)發(fā)者與優(yōu)化器之間的一場(chǎng)“雙人舞”:你通過(guò)特定的代碼寫(xiě)法去“引導(dǎo)”優(yōu)化器,從而在不犧牲任何安全性的前提下,獲得極高的性能。
我認(rèn)為在 C++ 領(lǐng)域,我們對(duì)這種優(yōu)化技巧討論得還遠(yuǎn)遠(yuǎn)不夠,因?yàn)槲覀冊(cè)趦?nèi)存安全這條路上才剛剛起步。但我相信,同樣的原理和機(jī)制在 C++ 中也是完全適用的。
吳詠煒:我認(rèn)為在這種情況下,有一個(gè)參考實(shí)現(xiàn)真的很有幫助,因?yàn)槲瘑T會(huì)知道他們可以讓編譯器基于靜態(tài)分析進(jìn)行這樣的優(yōu)化,對(duì)吧?
David Sankel:對(duì)。是的。
吳詠煒: 好的。非常感謝您接受今天的采訪。
David Sankel:謝謝。
《近匠》是 CSDN 推出的訪談欄目,其意思即為「走近工匠」,走近深耕于開(kāi)源、云、AIoT、根技術(shù)、數(shù)字化轉(zhuǎn)型、前沿技術(shù)的工具創(chuàng)造者和技術(shù)管理者們,了解他們?cè)趺纯创F(xiàn)在的開(kāi)發(fā)工作,分享自己精雕細(xì)琢出來(lái)的工具有何特點(diǎn),剖析整個(gè)行業(yè)發(fā)展現(xiàn)狀及未來(lái)趨勢(shì)。
為此,基于 AI、開(kāi)源、系統(tǒng)軟件、數(shù)字化轉(zhuǎn)型、前沿技術(shù)等領(lǐng)域,如果您及團(tuán)隊(duì)有報(bào)道需求,亦或者如果您有對(duì)技術(shù)趨勢(shì)的真知灼見(jiàn),或是深度的應(yīng)用實(shí)踐、場(chǎng)景方案等的新見(jiàn)解,歡迎聯(lián)系 CSDN 投稿,聯(lián)系方式:微信(hanbb120,請(qǐng)備注投稿+姓名+公司職位)、郵箱(tumin@csdn.net)。
未來(lái)沒(méi)有前后端,只有 AI Agent 工程師。
這場(chǎng)十倍速的變革已至,你的下一步在哪?
4 月 17-18 日,由 CSDN 與奇點(diǎn)智能研究院聯(lián)合主辦「2026 奇點(diǎn)智能技術(shù)大會(huì)」將在上海隆重召開(kāi),大會(huì)聚焦 Agent 系統(tǒng)、世界模型、AI 原生研發(fā)等 12 大前沿專(zhuān)題,為你繪制通往未來(lái)的認(rèn)知地圖。
成為時(shí)代的見(jiàn)證者,更要成為時(shí)代的先行者。
奇點(diǎn)智能技術(shù)大會(huì)上海站,我們不見(jiàn)不散!
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶(hù)上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.