首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

Effective C++ 條款 45-48 深度解析

     編輯:C++ 入門

條款 45:弄清 C++ 默默編寫並調用哪些函數

對於一個空類 class Empty {},編譯器會隱式生成以下 public 成員函數:

  • 默認構造函數 Empty()
  • 拷貝構造函數 Empty(const Empty&)
  • 拷貝賦值運算符 Empty& operator=(const Empty&)
  • 析構函數 ~Empty()(非 virtual,除非基類有 virtual 析構)
  • 取址運算符 operator&()(const 和非 const 版本)

關鍵行為

  • 默認構造/析構:不做任何事(不初始化成員)。
  • 拷貝構造/賦值:逐成員淺拷貝(memberwise copy)。
  • 含 const、reference 或無默認構造的成員時,編譯器拒絕生成對應函數(報錯)。
  • 含指針成員時:淺拷貝導致雙重釋放風險,需自定義深拷貝。
  • 將派生類的拷貝/賦值聲明為 private 可阻止編譯器為其生成對應函數(C++11 可用 = delete)。

條款 46:寧可編譯/鏈接報錯,勿讓錯誤延至運行期

C++ 無運行期檢查機制,運行期錯誤(如空指針解引用、越界)極難定位。策略:

  • 引入強類型:用類封裝約束,將合法性檢查前移至編譯期。
  • 例:Date(int d, Month m, int y) 中 Month 為類而非 enum 或 int,構造函數 private,只提供 static Month Jan() 等工廠方法,杜絕非法月份值構造。
  • 雖無法消除所有運行期檢查(如指針解引用前的空檢查),但盡量將錯誤「左移」到編譯/鏈接階段,程序更小、更快、更可靠。

條款 47:確保非局部靜態對象在使用前被初始化

非局部靜態對象:全局/命名空間變量、類靜態成員、文件級 static 變量。跨編譯單元的初始化順序未定義,易導致「初始化順序災難」。

單例模式解法(Meyers Singleton)

class Country { /* ... */ };
Country& theCountry() {
    static Country instance;  // 首次調用時初始化,線程安全 (C++11)
    return instance;
}
// 使用時:theCountry().doSomething();

優勢:

  1. 利用函數局部靜態變量的明確初始化時機(首次進入函數)。
  2. 若從未調用,零開銷(無構造/析構)。
  3. 解決跨翻譯單元依賴順序問題。

條款 48:重視編譯器警告

  • 開啟最高警告等級(/W4 MSVC, -Wall -Wextra -pedantic GCC/Clang)。
  • 理解警告含義:如 B::f() hides virtual A::f() 提示派生類非 const 重載隱藏了基類 const 虛函數,導致多態失效。
  • 不同編譯器警告覆蓋面不同(VS2012 未報上述警告),建議多編譯器交叉編譯。
  • 將警告視為錯誤(/WX / -Werror)強制修復。

總結表

條款核心建議關鍵技術
45掌握編譯器隱式生成的六大函數行為淺拷貝、const/ref 成員限制、private 禁用生成
46錯誤前移至編譯期強類型封裝、private 構造+工廠方法
47消除非局部靜態初始化順序依賴Meyers Singleton (函數局部 static)
48零容忍編譯器警告高警告級、多編譯器、警告即錯誤
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved