天天看點

Effective C++ 讀書筆記之Part5.Implementations

 26. Postpone variable definitions as long as possible.

總結:

盡可能延後變量定義式的出現。這樣做可增加程式的清晰度并改善程式效率。

批注:

純C語言此處有沖突,C語言要求變量定義出現在代碼快的開始部分。

27. Minimize casting.

1)const_cast 通常被用來将對象的常量性轉除(cast away the constness) 。它也是唯一有此能力的 C++-style 轉型操作符。

2)dynamic_cast主要用來執行"安全向下轉型"( safe downcasting) ,也就是用來決定某對象是否歸屬繼承體系中的某個類型。它是唯一無法由舊式文法執行的動作,也是唯一可能耗費重大運作成本的轉型動作。

3)reinterpret_cast 意圖執行低級轉型,實際動作(及結果)可能取決于編譯器,這也就表示它不可移植。例如将一個 pointer to int 轉型為一個 int 。這一類轉型在低級代碼以外很少見。本書隻使用一次,那是在讨論如何針對原始記憶體 (rawmemory) 寫出一個調試用的配置設定器 (debugging allocator) 時,見條款50。

4)static_cast 用來強迫隐式轉換 (implicit conversions) ,例如将 non-const對象轉為 const 對象(就像條款3 所為) ,或将 int 轉為 double 等等。它也可以用來執行上述多種轉換的反向轉換,例如将void*指針轉為 typed 指針,将pointer-to-base 轉為 pointer-to-derived。但它無挂将 const 轉為 non-canst'一一這個隻有const_cast 才辦得到。

第一,如果可以,盡量避免轉型,特别是在注重效率的代碼中避免dynamic_casts。如果有個設計需要轉型動作,試着發展無需轉型的替代設計。

第二,如果轉型是必要的,試着将它隐藏于某個函數背後。客戶随後可以調用該函數,而不需要将轉型放進他們自己的代碼内。

第三,甯可使用C++-style(新式)轉型,不要使用舊式轉型。前者很容易辨識出來,而且也比較有着分們别類的職掌。

28.Avoid returning "handles" to object internals.

避免傳回handles(包括references、指針、疊代器)指向對象内部。遵守這個條款可增加封裝性,幫助const成員函數的行為像個const,并将發生“虛吊号碼牌”(dangling handles)的可能性将至最低。

虛吊号碼牌應該指的就是指向的對象已經被銷毀了,但是傳回的指針或者引用還在使用。

29.Strive for exception-safe code.

當異常被抛出時。帶有異常安全性的函數會:

1)不洩露任何資源。

2)不允許資料被毀壞。

異常安全函數(Exception-safe functions)提供以下三個保證之一:

1)基本承諾:如果異常被抛出,程式内的任何事物仍然保持在有效狀态下。

2)強烈保證:如果異常被抛出,程式狀态不改變。

3)包抛擲(nothrow)保證:承諾絕不抛出異常,因為他們總能完成它們原先承諾的功能。

copy and swap原則:為你打算修改的對象(原件)做出一份副本,然後在那副本身上做一切必要修改。若有任何修改動作抛出異常,原對象仍保持未改變狀态。待所有改變都成功後,再将修改過的那個副本和原對象在一個不抛出異常的操作中置換(swap)。

第一,異常安全函數(Exception-safe functions)即使發生異常也不會洩漏資源或允許任何資料結構敗壞。這樣的函數區分為三種可能的保證:基本型、強烈型、不抛異常型。

第二,“強烈保證”往往能夠以copy-and-swap實作出來,單“強烈保證”并非對所有函數都可實作或具備現實意義。

第三,函數提供的“異常安全保證”通常最高隻等于其所調用哪個之各個函數的“異常安全保證”中的最弱者。

在現實程式的使用中,一般要求達到強烈型即可。因為基本型可能會導緻一些不再使用的資料殘留下來。而不抛異常型因為實作過于複雜的原因,一般也不達到這個級别。

30.Understand the ins and outs of inlining.

inline函數北周的整體觀念是,将“對此函數的每一個調用”都以函數本體替換之。

inline函數通常一定被置于頭檔案内,大多數編譯器會在編譯期時候完成inlining,有些編譯器會在連結期完成inlining,甚至有些編譯器會在運作的時候完成inlining.

Templates通常也被置于頭檔案中,因為它一旦被使用,編譯器為了将它具體化,需要知道它長什麼樣子。有些編譯器會在連結期才執行template具體化,但是大多數情況下還是在編譯器實作的具體化。

一個表面上看似inline的函數是否真是inline,取決于你的建置環境,主要取決于編譯器。大多數的編譯器提供了一個診斷級别:如果它們無法将你要求的函數inline化,會給你一個警告資訊。

第一,将大多數inlining限制在小型、被頻繁調用的函數身上。這可使日後的調試過程和二進制更新(binary upgradability)更容易,也可使潛在的代碼膨脹問題最小化,使程式的速度提升機會最大化。

第二,不要隻因為function templates出現在頭檔案,就将它們聲明為inline。

templates和inline沒有必然關系,需要加以區分。

31.Minimize compilation dependencies between files.

編譯依存關系   compilication dependency

連串編譯依存關系  cascading compilation dependencies

第一,支援“編譯依存性最小化”的一般構思是:相依于聲明式,不要相依于定義式。基于此構想的兩個手段是Handle classes和Interface classes.

第二,程式庫頭檔案應該以“完全且僅有聲明式”(full and declaration-only forms)的形勢存在。這種做法不論是否涉及templates都适用。

感悟:

這本書對于有一定的代碼量的人會有很大的幫助,如果代碼量不夠的話,看起來會覺的很不好了解,也不容易記住這麼多條款。當然,即使代碼量夠了,這本書也不是看一遍就可以扔了的,是屬于可以放在案頭不斷的翻閱,直到這些條款的内容都融入骨髓。這部分的内容,我最大的感受就是很多東西在帶來有利的一面的時候也帶來了不利的一面,是以在使用的過程中要仔細的推敲,到底如何去用。沒有哪種用法就一定萬無一失,就一定會更好,要看具體使用的環境。

繼續閱讀