【讀書筆記】Effective C++(05)實現

作者:LogM

本文原載於 https://segmentfault.com/u/logm/articles,不允許轉載~

5. 實現

  • 5.1 條款26:儘可能延後變量定義式出現的時間

    • std::string encryptPassword(const std::string& password) {
          using namespace std;
          string encrypted;   //bad,過早定義,如果下一句出異常,這個變量其實沒有用到,導致無謂的構造和析構
          if (password.length() < MinimumPasswordLength) {
              throw logic_error("Password is too short");
          }
          ...   //加密過程
          return encrypted;
      }
      
      std::string encryptPassword(const std::string& password) {
          using namespace std;
          if (password.length() < MinimumPasswordLength) {
              throw logic_error("Password is too short");
          }
      
          string encrypted;   //ok,要用到時再定義
          ...  //加密過程
          return encrypted;
      }
    • //循環內的變量怎麼定義?
      
      //方法A:定義於循環外
      Widget w;
      for (int i=0; i<n; ++i) {
          w = ...;
          ...
      }
      
      //方法B:定義於循環內
      for (int i=0; i<n; ++i) {
          Widget w(...);
          ...
      }
      
      //方法A:1個構造函數、1個析構函數、n個賦值操作,變量w作用域覆蓋到循環以外
      //方法B:n個構造函數、n個析構函數,變量w作用域僅在循環內
      //具體使用哪個視情況而定。
      
      //我自己想了一個非常小衆的寫法,雖然可以兼得方法A和方法B的長處,但是代碼可讀性降低
      for (int i=0, Widget w; i<n; ++i) {
          w = ...;
          ...
      }
  • 5.2 條款27:儘量少做轉型動作

    • C++的新式轉型:

      • a. const_cast<...>(...)。移除對象的常量性。
      • b. dynamic_cast<...>(...)。在繼承體系中進行安全的向下轉型,效率低。
      • c. reinterpret_cast<...>(...)。低級轉型,結果取決於編譯器,不可移植。
      • d. static_cast<...>(...)。強迫執行隱式轉換,類似於C中的舊式轉換。
    • 作者提醒,只有明確知道轉型後的結果是什麼時才使用轉型,自以爲是地猜測轉型的結果往往導致錯誤。
  • 5.3 條款28:避免返回值是指向 private 成員變量的引用或者指針

    • 很容易理解,如果成員函數返回值是指向 private 成員變量的引用或者指針,那麼成員變量的 private 不再具有意義,它實際能被修改。
    • 解決方法是將返回的引用或指針設爲const類型,禁止修改。
    • 有些特殊情況下,返回的引用或指針指向的成員變量被銷燬,導致引用和指針無效(dangling handles),這種情況要在代碼中避免。
  • 5.4 條款29:保證"異常安全"

    • 異常安全的函數,即使在發生異常的時候也能保證不泄漏資源不破壞數據結構,可以分爲三種:

      • a. 基本型:保證資源不泄露,保證數據結構不破壞,但異常發生後程序中的對象的狀態是未知的;
      • b. 強烈型:在基本型的基礎上,保證如果出現異常,程序中的對象的狀態會回覆到"調用該函數前"的狀態;
      • c. 不拋異常型:承諾所有異常都能被處理,不拋出異常。
    • 實際使用時,要綜合考慮效率和安全性來確定使用哪一種類型的異常安全。
  • 5.4 條款30:透徹理解inline函數

    • inline函數:編譯器用inline函數的本體代碼替換程序中的每一次調用。因此,濫用inline函數將導致程序體積過大,進而降低高速緩存命中率等導致效率降低。
    • inline函數的實現應該寫在.h頭文件中,因爲大多數編譯器是在編譯期處理inline函數的。(與template類似,template的聲明和實現也應該放在頭文件中,但這不意味着template就一定是inline)
    • virtual函數不能使用inline,因爲virtual是運行期才能確定的。
    • inline的缺點:a. inline函數無法隨着程序庫的升級而升級,必須重新編譯;b. inline函數的調試很麻煩。
    • 什麼時候用inline:當整個程序的大量運行時間耗費在某段代碼的調用過程上時。
    • 即使你寫成inline函數,編譯器也有權力不編譯爲inline形式。
  • 5.5 條款31:將文件間的編譯依存關係降到最低

    • 原因:當改動一個文件後,不需要整個工程都重新編譯。
    • 常見的"把類的定義和聲明放在兩個文件中",就是減少編譯依存關係的一個例子。
發佈了52 篇原創文章 · 獲贊 19 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章