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