C++ 從基礎到精通 — 第 23 講
以建置、測試、Sanitizer 與分析完成精通專案
本部落格文章以教學為目的撰寫。 內容可能有誤,請搭配目標編譯器與標準函式庫文件確認。
精通不是堆滿高階語法,而是能以可重現證據說明需求、生命週期、失敗與效能。最後專案將整個系列整合為非同步資源串流系統。
Capstone 契約
request → 去重 → 讀檔 → decode → GPU upload → cache
│ │ │
取消/錯誤 worker pool 主執行緒邊界
- 同一資源鍵的並行請求共享一個操作。
- 所有等待者都取消時停止不必要工作。
- 檔案 bytes、decode buffer 與 GPU 物件有明確所有者。
- Worker 結束後 callback 不得接觸已銷毀狀態。
- 保留錯誤類別與是否可重試。
- 以代表性 workload 測量時間、記憶體與配置目標。
讓依賴向內
include/streaming/ 公開契約、handle、錯誤型別
src/core/ 狀態機與去重
src/io/ 檔案系統 adapter
src/decode/ 圖像 decoder adapter
src/gpu/ render-thread adapter
tests/ 單元、整合與 race 測試
benchmarks/ 可重現 workload
核心狀態機不直接依賴圖形 API 或檔案系統,而是接收小型介面或受限型別,測試則注入可決定順序的 fake。
Header 中的 inline 函式與模板必須在每個 translation unit 保持等價定義。改變公開物件 layout 或虛擬函式順序可能破壞 ABI,因此 shared library 邊界需要版本與重建政策。
用工具重現失敗
-fsanitize=address,undefined -fno-omit-frame-pointer
-fsanitize=thread
AddressSanitizer 協助找出生命週期與越界錯誤,UndefinedBehaviorSanitizer 回報多類 undefined behavior,ThreadSanitizer 尋找 data race。ASan 與 TSan 通常使用不同建置,平台支援也不同。
必要失敗測試包含空檔、損壞資料、取消與完成競爭、重複請求、worker 結束及 allocator 耗盡。使用 barrier、fake executor 與可控制 callback,而不是依賴 sleep。
Profile 用來驗證假設
記錄 CPU、OS、編譯器版本與選項、輸入、命令、重複次數和原始結果。除了平均值,也檢查 p50/p95 latency、peak memory、配置次數與 throughput。
從 profile 選一個瓶頸,一次只改一項,再比較正確性與資源。std::move、自訂 allocator 與 lock-free 結構都需要證據。
完成條件
- 以圖說明所有權與 thread affinity。
- 每個工作都有成功、失敗、取消與關閉路徑。
- 用自動測試與 Sanitizer 檢查 race 和生命週期錯誤。
- 從乾淨環境重現 configure、build、test。
- 以 ADR 保存前後數據、捨棄方案與限制。
精通 C++ 不是背下語言所有角落,而是用型別表達值與資源生命週期,控制並行與失敗邊界,並根據編譯器、測試、Sanitizer 與 profiler 的證據持續修正設計。