大多數情況下,適當提出你的classes(和class templates)定義以及functions(和function templates)宣告,是花費最多心力的地方。一旦正確完成它們,相應的實現大多直截了當。儘管如此,還是有些東西需要小心。太快定義變數可能造成效率上的拖延;過度使用轉型(casts)可能導致**變慢又難維護,可能招來微妙難解的錯誤;返回物件「內部資料之號令牌(handles)」可能會破壞封裝並留給客戶虛吊號碼牌(dangling handles);未考慮異常帶來的衝擊則可能導致資源洩漏和資料敗壞;過度熱心地inlining可能會引起**膨脹;過度耦合(coupling)則可能導致讓人不滿意的冗長建置時間(build times)
二十
六、條款26-盡可能延後變數定義式的出現時間
1.只要你定義了乙個變數而其型別帶有乙個建構函式或析構函式,那麼當程式的控制流(control flow)到達這個變數定義式時,你便得承受構造成本;當這個變數離開其作用域時,你便得承受析構成本。即使這個變數最終並未被使用,仍需耗費這些成本,所以你應該盡可能避免這種情形
2.對於for迴圈,做法一是定義於迴圈體外,做法二是定義於迴圈體內。除非(1)你知道做法一整體成本比做法二整體成本低,(2)你正在處理**中效率高度敏感的部分,否則你應該使用做法二。做法一的變數名作用域比做法二大,有時那對程式的可理解性和易維護性造成衝突
3.盡可能延後變數定義式的出現。這樣做可增加程式的清晰度並改善程式效率
二十
七、條款27-盡量少用轉型動作
1.舊式轉型仍然合法,但新式轉型較受歡迎。原因是:第一,它們很容易被辨識出來,因而得以簡化「找出型別系統在哪個地點被破壞」的過程。第二,各轉型動作的目標愈窄化,編譯器愈可能診斷出錯誤的運用
2.單一物件(例如乙個型別為derived的物件)可能擁有乙個以上的位址(例如「以base*指向它」時的位址和「以derived*指向它」時的位址)
3.如果你發現你自己打算轉型,那活脫是個警告訊號:你可能正將局面發展至錯誤的方向上。如果你用的是dynamic_cast更是如此
4.除了對一般轉型保持機敏與猜疑,更應該在注重效率的**中對dynamic_cast保持機敏與猜疑(dynamic_cast的許多實現版本執行速度相當慢)
5.如果可以,盡量避免轉型,特別是在注重效率的**中避免dynamic_casts。如果有個設計需要轉型動作,試著發展無需轉型的替代設計
6.如果轉型是必要的,試著將它隱藏於某個函式背後。客戶隨後可以呼叫該函式,而不需要將轉型放進他們自己的**內
7.寧可使用c++-style(新式)轉型,不要使用舊式轉型
二十
八、條款28-避免返回handles指向物件內部成分
1.避免返回handles(包括references、指標、迭代器)指向物件內部。遵守這個條款可增加封裝性,幫助const成員函式的行為像個const,並將發生「虛吊號碼版」(dangling handles)的可能性降至最低
二十
九、條款29-為「異常安全」而努力是值得的
1.有個一般化的設計策略很曲型地會導致強烈保證,很值得熟悉它。這個策略被稱為copy and swap。原則很簡單:為你打算修改的物件(原件)做出乙份副本,然後在那副本身上做一切必要的修改。若有任何修改動作丟擲異常,原物件仍保持未改變狀態。待所有改變都成功後,再將修改過的那個副本和原物件在乙個不丟擲異常的操作中置換(swap)
2.當異常丟擲時,帶有異常安全性的函式會:(1)不洩漏任何資源 (2)不允許資料敗壞。這樣的函式區分為三種可能的保證:基本型、強烈型、不拋異常型
3.「強烈保證」往往能夠以copy-and-swap實現出來,但「強烈保證」並非對所有函式都可實現或具備現實意義
4.函式提供的「異常安全保證」通常最高只等於其所呼叫之各個函式的「異常安全保證」中的最弱者
三
十、條款30-透徹了解inlining的裡裡外外
1.乙個表面上看似inline的函式是否真是inline,取決於你的建置環境,主要取決於編譯器。幸運的是大多數編譯器提供了乙個診斷級別:如果它們無法將你要求的函式inline化(如太過複雜(還有迴圈或遞迴)的函式、所有對virtual函式的呼叫等,inline是編譯期行為),會給你乙個警告資訊(見條款53)
2.將大多數inlining限制在小型、被頻繁呼叫的函式身上。這可使日後的除錯過程和二進位制公升級更容易,也可使潛在的膨脹問題最小化,使程式的速度提公升機會最大化
3.不要只因為function templates出現在標頭檔案,就將它們宣告為inline
4.不要忘記80-20經驗法則:平均而言乙個程式往往將80%的執行時間花費在20%的**上頭。這是乙個重要的法則,因為它提醒你,作為乙個軟體開發者,你的目標是找出這可以有效增進程式整體效率的20%**,然後將它inline或竭盡所能的將它**。但除非你選對目標,否則一切都是虛功
三十
一、條款31-將檔案間的編譯依存關係降至最低
1.「以宣告依存性」替換「定義的依存性」,那正是編譯依存性最小化的本質:現實中讓標頭檔案盡可能自我滿足,萬一做不到,則讓它與其他檔案內的宣告式(而非定義式)相依。其他每一件事都源自於這個簡單的設計策略:
[1]如果使用object references或object pointers可以完成任務,就不要使用objects
[2]如果能夠,盡量以class宣告式替換class定義式
[3]為宣告式和定義式提供不同的標頭檔案
2.支援「編譯依存性最小化」的一般構想是:相依於宣告式,不要相依於定義式。基於此構想的兩個手段是handle classes和inte***ce classes
3.在程式開發過程中使用handle classes和inte***ce classes以求實現碼有所變化時對其客戶端帶來最小衝擊。而當它們導致速度和/或大小差異過於重大以至於classes之間的耦合相形之下不成為關鍵時,就以具象類(concrete classes)替換handle classes和inte***ce classes
《effective C 》讀書筆記
1,c 關鍵字explicit c 中,乙個引數的 建構函式 或者除了第乙個引數外其餘引數都有預設值的多參建構函式 承擔了兩個角色。1 是個 構造器,2 是個預設且隱含的型別轉換操作符 所以,有時候在我們寫下如 aaa 這樣的 且恰好 的型別正好是aaa單引數構造器的引數型別,這時候 編譯器就自動呼...
Effective C 讀書筆記
一 讓自己習慣c 1 條款01 視c 為聯邦語言 c 的組成可分為四部分 1.c c 仍然以c語言為基礎。區塊 語句 預處理 內建資料型別 陣列 指標等都來自c。2.object oriented c c with classes所訴說的 classes 包括構造和析構 封裝 繼承 多型 virtu...
讀書筆記 Effective C
部分條款過於深奧,部分條款已了然於心,僅記錄當下所識所學 對於常量巨集定義,最好用const代替 define 對於函式巨集定義,最好用inline代替 define include ifdef ifndef仍被需要 內建物件記得手動初始化 使用成員初始列替換賦值操作 以local static替換...