作者: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中的舊式轉換。
- a.
- 作者提醒,只有明確知道轉型後的結果是什麼時才使用轉型,自以爲是地猜測轉型的結果往往導致錯誤。
-
-
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:將文件間的編譯依存關係降到最低
- 原因:當改動一個文件後,不需要整個工程都重新編譯。
- 常見的"把類的定義和聲明放在兩個文件中",就是減少編譯依存關係的一個例子。