系統程式設計師的 C++

零開銷原則(the zero-overhead principle)

有種恐懼認為高階的便利必然犧牲效能——類別、模板與智慧指標是以速度為代價買來可讀性。C++ 圍繞一個反駁這點的承諾建構,Bjarne Stroustrup 通常把它總結成兩部分:第一,你不為你不使用的東西付費;第二,你確實使用的東西,你再怎麼手工編寫也不會更好。這就是零開銷原則,它解釋了為什麼 C++ 力求給你抽象卻不收抽象稅。

具體而言,「不為你不使用的東西付費」意味著一個你從不調用的特性不對你的程式施加任何成本——若你不丟例外,正常路徑全速運行;若你不用虛擬函式,就沒有 vtable 指標或間接呼叫。而「你使用的東西和手工編寫一樣有效率」意味著這些抽象被設計成編譯出與專家手寫相同的機器碼:std::unique_ptr 和裸指標一樣大,它的解參考只是一次普通的載入;對 std::vector 的範圍式 for 編譯成與手寫索引相同的指標遞進迴圈;模板 max<int> 與手寫的整數 max 完全相同。編譯器的工作——內聯、單型化、最佳化——就是讓抽象蒸發。

為何重要:這個原則正是系統、遊戲與嵌入式程式設計師能使用現代 C++ 而不必退回 C 的原因——他們在保有 C 級別的記憶體與時間控制的同時,得到 RAII、型別安全與泛型。但誠實的提醒是真實的:零開銷是語言朝其設計的志向,而非每種情況下的保證。某些特性確實帶有固有成本(shared_ptr 的原子計數、throw 路徑上的執行期例外、虛擬分派),抽象只有在最佳化器執行後才是零成本(除錯、未最佳化的建構可能慢得多),而「相對於等效手寫程式碼的零開銷」不代表「免費」——它代表「不比你自己做同一件事更糟」。

for (int x : v) sum += x; // 對 std::vector<int> 的範圍式 for 編譯成與裸索引走訪 v 緩衝區相同的迴圈

高階構造最佳化成你會手寫的相同機器碼——抽象卻不收執行期稅。

零開銷是相對於等效手寫程式碼來衡量,不是相對於什麼都不做:一個做了實際工作的特性(原子參考計數、真正丟出的例外、虛擬呼叫)仍然要花費那份工作的代價。承諾是「不比你自己做更糟」,而非「神奇地免費」。

又称
don't pay for what you don't usezero-cost abstraction零成本抽象不為不用之物付費