C++ 編程規范:101條規則準則與最佳實踐
引言
C++ 是一門強大而復雜的語言,能高效控制硬件,也能寫出優雅抽象。然而,正因其復雜性,項目中若缺乏統一規范,極易陷入混亂、難維護、易出錯的泥潭。
本文總結了 101條 C++ 編程規范與最佳實踐 ,涵蓋 命名、結構、內存管理、多線程、異常、安全、性能等多個維度 ,旨在幫助開發者構建高質量、可維護、可擴展的 C++ 項目。
一、命名與風格(Rules 1–10)
# 規則 簡要建議 1 類名使用大駝峰 PascalCase
如 ThreadPool
,提高可辨識性 2 變量名使用小駝峰 camelCase
例:logFilePath
,區分于類名 3 常量用 ALL_CAPS
+ _
分隔 強化不變含義,如 MAX_BUFFER_SIZE
4 命名需語義明確 避免 data
, tmp
,使用 configFilePath
更清晰 5 縮寫僅限通用縮寫 如 idx
, buf
,盡量使用全稱提升可讀性 6 函數名用動詞 + 名詞 例如 loadConfig()
表意清晰 7 命名空間用小寫 如 network::socket
,避免歧義 8 接口類加 I
前綴(可選) 如 ILogger
,強調為接口 9 成員變量加前綴/后綴 m_
或 _
表示成員變量,增強可讀性10 用 enum class
替代裸 enum 強類型更安全,防止命名沖突
二、代碼結構與風格(Rules 11–20)
# 規則 簡要建議 11 每個頭文件只聲明一個模塊 避免多義性,便于編譯與復用 12 使用 #pragma once
或 include guard 防止重復包含 13 include 順序:本地 > 第三方 > STL 增強可讀性與可維護性 14 避免頭文件中包含過多實現 使用前向聲明可減少依賴 15 類/函數應單一職責 有助于測試與擴展 16 控制函數長度 < 60 行 超過建議拆分子函數 17 控制每個文件長度 < 2000 行 模塊化設計更清晰 18 每行不超過 120 字符 保證閱讀體驗,特別在 review 時 19 使用 4 空格縮進,禁止制表符 統一格式,防止跨平臺混亂 20 所有控制結構都用 {}
包圍 防止隱式邏輯錯誤,如單行 if 陷阱
三、類設計與對象管理(Rules 21–30)
# 規則 建議 21 所有成員變量應為私有 使用 getter/setter 訪問 22 提供合理構造/析構函數 保證資源初始化與釋放對稱 23 禁用復制/移動時應 = delete
明確意圖,防止誤用 24 用 explicit
阻止隱式轉換 如 explicit Config(std::string path)
25 避免裸指針作為成員 使用 unique_ptr
/shared_ptr
安全管理 26 構造函數不做復雜邏輯 僅初始化,不處理業務 27 基類析構函數應為 virtual
否則 delete 派生類有 UB 28 優先使用組合而非繼承 組合更靈活、低耦合 29 不使用多重繼承(除非純接口) 降低復雜度,避免菱形繼承問題 30 避免深層繼承結構 建議控制在 2 層以內
四、函數與模板(Rules 31–40)
# 規則 建議 31 參數多于 3 個建議封裝結構體 提高可讀性與擴展性 32 參數傳遞規則明確 小型值傳遞,大型對象引用 33 函數返回值推薦智能指針或值傳遞 避免裸指針和資源泄露 34 函數要寫用途注釋 特別是公共接口或庫函數 35 模板邏輯應輕量,避免過多嵌套 編譯時間壓力大時尤需注意 36 合理使用 auto
簡化類型 不影響語義的地方使用 37 模板中加入 static_assert
限定 增強類型安全性 38 使用 constexpr
提升編譯期能力 如常量計算函數 39 控制模板遞歸深度 編譯器對深層模板支持有限 40 模板盡可能放 header 中定義 避免鏈接錯誤(ODR 問題)
五、內存管理(Rules 41–50)
# 規則 建議 41 禁止裸 new/delete
用 make_unique
/make_shared
替代 42 所有資源管理用 RAII 讓析構自動釋放資源 43 禁止手動 free/close
封裝在類中自動釋放 44 指針擁有權應清晰 避免 ownership 混亂 45 避免 shared_ptr
在多線程競爭 使用 atomic_shared_ptr
或避免頻繁共享 46 使用工具檢測泄漏 如 Valgrind、ASan 47 使用智能指針區分 shared/unique 語義 更清晰,更安全 48 不要傳值傳遞 shared_ptr
用 const&
降低引用計數開銷 49 使用容器代替裸數組 STL 容器更安全 50 類封裝資源釋放邏輯 遵守 RAII,職責清晰
六、異常處理與錯誤傳遞(Rules 51–60)
# 規則 建議 51 盡量避免使用異常 推薦 error code / Result<T>
結構 52 異常必須 catch
并處理 記錄日志,避免 silent fail 53 不使用 catch (...)
易隱藏邏輯錯誤 54 構造函數中不拋異常 否則無法確定對象是否成功創建 55 明確錯誤處理模塊 集中統一處理錯誤 56 注釋中注明錯誤返回 增強調用方對異常的理解 57 編寫無副作用函數 降低調試/測試成本 58 日志輸出必須有上下文 包括文件名/函數名/線程信息 59 接口錯誤向上傳遞 不要在底層吞掉問題 60 異常路徑不得影響主邏輯性能 異常處理應輕量快捷
七、多線程與并發(Rules 61–70)
# 規則 建議 61 封裝線程操作 避免裸用 std::thread
62 原子操作使用 std::atomic
避免競態條件 63 使用細粒度鎖或無鎖結構 提升性能,減少死鎖 64 使用 lock_guard
管理鎖 自動加鎖釋放 65 不捕獲局部引用傳入線程 否則線程中變量懸空 66 避免死鎖 控制鎖順序,使用 std::scoped_lock
67 避免全局變量并發讀寫 用線程局部存儲或加鎖保護 68 構建線程池封裝并發任務 避免線程爆炸與資源浪費 69 不得在對象析構前 detach
線程 否則存在野線程 70 使用條件變量控制等待 避免忙等浪費 CPU
八、性能優化(Rules 71–80)
# 規則 建議 71 優化熱點路徑 代碼中使用 likely
/ unlikely
72 用 std::move
轉移資源 防止不必要的拷貝 73 使用 emplace_back
避免對象額外構造拷貝 74 使用 reserve
預分配空間 降低 reallocation 成本 75 避免頻繁申請釋放內存 推薦對象池或內存復用 76 避免虛函數熱路徑中使用 可用策略模式等替代 77 小函數可使用 inline
減少函數調用開銷 78 注意 ABI 兼容性 跨平臺或多版本部署需考慮 79 無序容器快于有序容器 unordered_map
通常優于 map
80 使用 string_view
避免拷貝 尤其在字符串解析場景中
九、安全與健壯性(Rules 81–90)
# 規則 建議 81 所有輸入必須校驗合法性 防止越界、注入等問題 82 檢查整數溢出風險 使用安全加法函數 83 禁止數組越界訪問 用 at()
或容器封裝 84 使用 RAII 管理資源 防止內存泄漏或懸空指針 85 IO 操作必須檢查返回值 否則容易邏輯錯誤 86 不在庫中使用 exit/abort
破壞調用者行為 87 庫中不處理 UI/日志 由上層決定策略 88 接口遵循最小權限原則 降低攻擊面與耦合 89 使用靜態分析工具輔助檢查 如 clang-analyzer, cppcheck 90 禁止未定義行為寫法 避免 UB 問題,如越界指針、懸空引用等
十、工程實踐與工具鏈(Rules 91–101)
# 規則 建議 91 接入持續集成(CI) 自動編譯與檢查保障質量 92 使用單元測試框架 推薦 GTest/GMock 93 使用代碼覆蓋率工具 識別未測試路徑 94 強制統一代碼格式化工具 推薦 clang-format
95 接入內存檢測工具 如 AddressSanitizer 96 使用 CMake 管理構建 跨平臺統一構建系統 97 單元測試覆蓋率 >= 80% 提升可靠性 98 所有代碼需 Code Review 防止低級錯誤 99 接入日志和監控模塊 如 Prometheus、Grafana 100 所有模塊應可獨立構建測試 降低耦合度 101 每半年重審一次規范 適應團隊與項目演化