Scott Meyers 的《Effective C++》被公認為 C++ 程序員必讀經典。55 條款涵蓋資源管理、類設計、模板泛型、繼承多態、並發等核心領域。本文提煉各章精華,結合現代 C++ (C++11/14/17/20) 視角,助你快速建立專業級編碼直覺。
const, enum, inline 替換 #define —— 宏無作用域、不進符號表、難調試;常量用 constexpr (C++11),函數用 inline/constexpr。const —— 讓編譯器幫你找錯;const 成員函數承諾邏輯不變狀態;mutable 配合緩存/鎖。local static 替換 non-local static 解決初始化順序災難。= delete,比私有未定義更清晰。virtual 析構函數 —— 核心鐵律,見條款 5 實驗三。std::terminate。virtual 函數 —— 此時虛表指針指向當前類,派生類覆寫不可見。operator= 返回 *this 引用 —— 支持鏈式賦值 a = b = c。operator= 中處理「自我賦值」 —— 比較地址、copy-and-swap 慣用語(強異常安全)。init() / copyFrom()。std::unique_ptr/shared_ptr 替代 auto_ptr (已移除)。=delete) 或引用計數 (shared_ptr) 或深拷貝,視語義而定。get() 更安全,隱式轉換更便利。new 和 delete 時采取相同形式 —— new[] 配 delete[],單對象配單 delete。new 出的對象置入智能指針 —— 避免 func(shared_ptr(new T), g()) 中 g() 拋異常導致洩漏。delete 不想要的重載、RAII 替換裸資源。pass-by-reference-to-const 替換 pass-by-value —— 避免切片、省拷貝;內置類型/迭代器/函數對象除外。private —— 封裝性、不變量、二進制兼容;protected 不比 public 更封裝。non-member, non-friend 替換 member 函數 —— 增加封裝、擴展性(如 std::begin/end)。non-member 函數 —— 隱式轉換對稱性(如 operator*)。swap —— pimpl、泛型代碼關鍵;提供 member swap + non-member swap + std::swap 特化。static_cast/dynamic_cast/reinterpret_cast/const_cast,隱藏在函數內。const 失效。copy-and-swap 實現強保證。inlining 裡裡外外 —— 小熱點函數內聯;頭文件模板非必須 inline;避免代碼膨脹、調試困難、二進制升級阻礙。Pimpl 慣用語、接口類、前置聲明、#include 最小化。public 繼承塑模出 is-a 關係 —— 基類契約對派生類必須成立;違反即設計錯誤。using Base::func 或轉發函數恢復。pure virtual 只繼承接口;impure virtual 繼承接口+默認實現;non-virtual 繼承接口+強制實現。virtual 函數以外的其他選擇 —— NVI (Template Method)、Strategy 模式 (std::function/lambda)、外部非成員函數。non-virtual 函數 —— 靜態綁定導致基類指針調用基類版本,語義混亂。has-a 或 is-implemented-in-terms-of —— 應用域 has-a,實現域 is-implemented-in-terms-of。private 繼承 —— 實現繼承(需訪問 protected/重寫 virtual);空基優化 (EBO) 省空間。virtual 繼承;介面類 public + 實現類 private 是常見合法模式。typename 的雙重意義 —— 模板參數 class/typename 可換;嵌套從屬類型必須加 typename (基類列表/初始化列表除外)。this->member 或 Base::member 延遲查找。void* + 模板包裝)。if-else (SFINAE/if constexpr (C++17)) 基石。new 和 deletenew-handler 行為 —— std::set_new_handler 設置分配失敗回調;nothrow new 僅覆蓋分配階段。new/delete 合理替換時機 —— 效能優化、堆診斷、內存池、對齊控制。new/delete 時需固守常規 —— 無限循環嘗試分配、調用 new_handler、處理 0 字節、類專屬版本檢查大小。placement new 也要寫 placement delete —— 構造拋異常時調用對應 delete 釋放內存,否則洩漏。iostream/locale、shared_ptr/function/regex/哈希容器等。55 條款非孤立技巧,而是構成一套連貫的 C++ 工程哲學:資源由對象管理、介面設計防誤用、泛型編程利用編譯期計算、繼承嚴守契約、異常安全分級保證。建議將其內化為代碼審查清單與重構指南,配合現代 C++ 標準庫特性(constexpr, span, concepts, coroutines...)持續演進。