第5條:一個實體應該只有一個緊湊的職責
單一職責原則。這個原則並不那麼容易執行,即使是STL這樣的程式庫,也一樣會犯違反該原則的錯誤。在這裡,舉了兩個違反這一原則的著名實現:realloc和stl 中的basic_string。不過,對於basic_string,我想比起MFC中的CString還是好了不少。在《Exceptional C++ style》中,對basic_string作了剖析,並且得出一個普遍的原則:盡量將函數實現為獨立的函數而不是成員函數。
嘗試用一句話來說明一個模組的功能,既不多,也不少。如果無法用這樣的一句話加以概括,那麼重新考慮規劃該模組的職責。
第6條:正確、簡單和清晰第一
簡單的說,堅持KISS原則:正確優於速度,簡單優於複雜,清晰優於機巧,安全優於不安全。
- 程式必須為閱讀它的人編寫,只是順便用於機器執行 * 編寫程式應該以人為本,電腦第二
- 電腦系統中最便宜、最快速、最可靠的組件都還不存在
- ......簡單設計的重要性怎麼強調也不過分
- 使一個正確的程式變快,比使一個快速的程式正確要容易的多
- 避免使用程式設計語言的冷僻特性,應該使用最簡單的有效技術
不要毫無節制地重載運算子。
不要濫用匿名變數,合理使用命名變數。當然,這不是說連vector().swap(other)這樣的慣用法也要排斥。
重構技術是改善代碼可讀性的有效手段。
第7條:編程中應知道何時和如何考慮延展性
從字面上來看,這差不多等於外交辭令。答案無非是“適當的”時候“適當地”考慮延展性。這非常依賴於軟體工程師的經驗和知識。所以,本條目也“適當地”迴避了那種缺乏營養的教導,著重討論演算法複雜度的選擇問題。
基本上,線性複雜度可以作為一個演算法是否可選的分界點。值得花費精力避免選擇差於線性複雜度的演算法,而不差於線性複雜度的演算法則可以接受。所以,把效能放在嘴邊的兄弟們注意了,你的精力可別放錯了地方,高德納言猶在耳:不成熟的最佳化是程式設計中的萬惡之源。必要時,先努力最佳化複雜度(選擇好的演算法----演算法無用論者,去面壁!)。
順便提一句排序演算法,通用排序演算法的複雜度最好是O(NlgN),但是特定領域完全可以有更好複雜度的演算法。
第8條:不要進行不成熟的最佳化
“不成熟的最佳化是程式設計中的萬惡之源” ----高德納引用的這句話這本書中出現了若干次,高德納在他的不朽名著《電腦程式設計藝術》中也一再強調了這一點,還說他以前程式中的許多錯誤都是關於不成熟最佳化的。看來,唯一在誘惑面前沒有墮落的,只有耶穌,即使是大師也無法抗拒。既然如此,建議把下面的話放在電腦案頭上:
讓一個正確的程式更快速,
比讓一個快速的程式正確,要容易的太多太多。
第9條:不要進行不成熟的劣化
什麼是不成熟的劣化呢?典型的有:
- 在可以通過引用傳遞的時候,卻定義了通過值傳遞參數。
- 在使用首碼++操作符很適合的場合,卻使用尾碼版本。
- 在建構函式中使用賦值操作而不是初始化列表。
關於第一條有一些例外,一般而言,不建議傳遞原生類型的引用(討論前提是傳值的程式語義沒有問題)。關於第二條,一些很老的C語言的書上有過尾碼版本可能比首碼版本更快----當然,這隻可能針對原生類型--的說法,忘記它吧,現代編譯器會輕而易舉最佳化掉這之間的差異。而對於使用者定義型別,實現尾碼形式的++和--操作符都意味著效率上的損失。習慣的力量是巨大的,養成使用首碼版本的習慣吧。
然而,要區別不成熟的最佳化和不成熟的劣化之間,需要足夠的訓練和基礎知識,這些知識可以從《Effective C++》,《More Effective C++》《Exceptional C++》《More Exceptional C++》中獲得。
第10條:盡量減少全域和共用資料
全域資料是應該努力避免的,它導致兩個問題:名字汙染和遠程耦合。類的公有靜態變數只是解決了名字汙染問題,並沒有解決遠端資料耦合問題。同樣,Singleton模式也存在遠程耦合問題。
全域資料通常就意味著共用,共用資料則意味著關係,意味著複雜性。再多線程中,對共用資料的訪問通常都需要序列化。
關於變數,一個比較深刻的看法是:一個演算法使用的變數(命名的和匿名的)越少,就越好。這個變數包括局部變數。
第11條:資訊隱藏
對於一個類,決不要將資料公開(數值彙總的struct 例外),也不要返回指向內部資料成員的指標或引用供外部代碼修改。通過提供抽象,我們將獲得插入不變式檢查的能力。
第12條:懂得何時和如何進行並發性編程
這個問題主要是考慮多線程和多進程的編程,我期待著並行程式設計進入C++的領域。要編寫正確、安全的多線程代碼並不簡單,特別是考慮到可移植性時,更是如此。
不過,本條目的題目太大了,很難在一個條目中描述完整,只能概述幾個要點:
- 參考目標平台文檔,瞭解該平台的同步化原語。
- 最好將平台原語用自己設計的抽象封裝起來
- 確保正在使用的類型在多線程程式中使用是安全的
第13條:確保資源為對象所擁有。使用顯式的RAII和智能指標
好像是在《Imperfact C++》中說過:僅僅因為有RAII就值得使用C++。C++/CLI也強調引入確定性析構,確定性析構正式RAII得以實現的基礎之一。通過RAII我們能夠得到的遠遠超出一般程式員的想象,在討論異常安全的程式碼時,將進一步見識RAII的威力。
在實現RAII時,需要小心複製構造和賦值,編譯器的版本可能並不正確。另外,需要確保資源為對象所有,不要在一行分配一個以上的資源。下面的代碼是不安全的:
Fun(shared_ptr<Widget>(new Widget), shared_ptr<Widget>(new Widget));
取而代之的正確方法是:
shared_ptr<Widget> sp1(new Widget), sp2(new Widget);
Fun(sp1, sp2);
http://blog.csdn.net/wingfiring 非典型禿子