絕對不要對無效的迭代器執行解引用(dereference)操作
用于不要將異常安全性放在事后考慮。異常安全性會影響到類的設計。它永遠都不會“只是一個實現細節”。
在傳遞對象參數時,選擇const&方式而不是傳值方式。
對于程序運行中不會改變的值,應該預先計算并保存起來備用,而不是重復地創建對象,這是沒有必要的。
通常,為了保持一致性,應該使用前置遞增來實現后置遞增,否則,當其他用戶在使用你的類時,可能會得到奇怪結果。
優先選擇使用前置遞增。只有在需要初始值時,才使用后置遞增。
在進行隱式類型轉換時,要注意在轉換過程中創建的 臨時對象。要避免這個問題,一個好辦法就是盡可能地通過顯式的方式來構造對象,并避免編寫類型轉換運算符。
記住對象的生存期。永遠,永遠,永遠都不要返回指向局部對象的指針或引用;它們沒有任何用處,因為主調代碼無法跟蹤它們的有效性,但卻可能會試圖這么做。
盡可能地重用代碼——尤其是標準庫中的代碼——而不是自己去編寫代碼,這樣更快、更容易,也更安全。
如果在函數中不打算處理所拋出的異常,那么應該將異常轉發給能夠進行處理的上層調用者。
在編寫代碼時應該始終遵循:即使在出現異常時,資源仍然能夠被正確地釋放,并且數據也總是處于一致的狀態。
遵循標準的異常安全規則:永遠不要在析構函數、重載運算符函數operator delete()或者operator delete[]()中拋出異常; 在編寫每個析構函數和內存釋放函數時,要假設存在著“throw()”這樣的異常規范。
遵循標準的異常安全性規則:在每個函數中,要將所有可能會拋出異常的代碼單獨放在一起,并且對這些代碼進行安全處理。然后,當你確認這些代碼執行的工作都已經成功地完成時,才可以使用不會拋出異常的操作來修改程序的狀態。
永遠都不要到最后才實現異常安全性。異常安全性會對類的設計產生影響。它永遠都不會“只是一個實現細節”。
優先考慮實現內聚。要努力使每段代碼——每個模塊、每個類、每個函數——都只有單一的,并且是明確定義的功能。
“異常不安全”總是與“拙劣的設計”結伴的。如果程序的設計邏輯清晰,那么即使有一段代碼不是異常安全的,一般來說也不會有太大問題,并且可以很簡單地進行修正。但如果有一段代碼由于設計問題而不能被編寫成異常安全的,我們通常都會認為這個設計時拙劣的。下面是兩個拙劣設計的示例。
示例1:如果在一個函數中需要實現兩個不同的功能,那么這個函數很難被編寫成異常安全的。
示例2:如果在拷貝賦值運算符函數中必須對自我賦值進行檢測,那么這個函數也可能不是完全異常安全的
遵循標準的異常安全性規則:以“獲得資源也就意味著初始化”這種模式來分離資源的所有權和資源的管理權。
在進行設計中,要始終牢記重用性。
優先采用“ a op=b;”這種寫法,而不是"a = a op b;"(這里的op表示某個運算符)。這種寫法更為清晰,效率也高。
如果定義了某個運算符(例如,operator+),那么通常還應該同時定義與這個運算符相對應的賦值運算符(例如,operator+=)。并且用后者來實現前者。而且,還應該維護op和op=之間的自然關系。
在C++標準中規定:運算符=,(),[]和->必須被定義為成員函數,而在類中定義的new,new [],delete和delete[]等運算符函數必須是靜態成員函數。對于其他的運算符函數:
如果運算符函數是用于流I/O的opeator>>或者operator<<,或者如果運算符函數需要對其左操作數進行類型轉換,或者運算符函數可以通過類的公有接口來實現,那么將這個函數定義為非成員函數(在前兩種情況中,如果需要的話也可以被定義為友元函數);如果運算符函數需要實現虛函數的行為,那么增加一個虛函數來提供虛函數的行為,并用這個虛成員函數來實現運算符函數否則將預算富函數定義為成員函數。
在函數opeator>>和operator<<中應該始終返回對流對象的引用。
將基類的析構函數定義為虛函數(除非你能保證,永遠都不會有人通過指向基類的指針來刪除派生類的對象)。
如果在派生類中定義的函數與基類中的函數有相同的名字,并且你不想隱藏基類中函數,那么應通過using聲明語句將基類的這個函數引入到派生類的作用域中。
永遠不要改變被覆蓋的基類函數中的默認參數值。
除了對真正的Liskov IS-A和WORKS-LIKE-A關系進行建模之外,永遠都不要使用共有繼承。所有被覆蓋的成員函數不能超過實際需求的范圍,同時也不能小于這個范圍。
使用公有繼承的目的是重用代碼(編寫以多態的方式使用基類對象的代碼),而重用(基類中的)代碼并不一定要使用公有繼承。
對“is implemented in terms of”這種關系建模時,應該優先選擇成員關系/包含的方式,而不是私有繼承的方式。只有非用繼承不可時,才應該使用私有繼承——也就是說,當需要訪問保護成員或者需要覆蓋虛函數時,才使用私有繼承。永遠都不要只是為了代碼重用而使用共有繼承。
對于廣泛使用的類,應該優先使用編譯器防火墻這種慣用法(也叫做Pimpl慣用法)來隱藏實現細節,通過一個不透明的指針(指向一個進行了前置聲明但又沒有定義的類)來保存私有成員(包括狀態變量和成員函數),聲明這個指針時可采用“struct XxxxImpl* pImpl;XxxxImpl* pimpl_;”這樣的形式。例如:“class map{ private :struct MapImpl;MapImpl* pimpl_;}”
包含,也可以叫做“聚合”,“分層”,“HAS-A”或者“委托”。優先選擇包含而不是繼承,對于IS-IMPLEMENTED-IN-TERMS-OF這種關系建模時,應該優先考慮使用包含,而不是繼承。