《Effective C++》讀書摘要
最近剛讀完侯捷的《Effective C++》,相對來說,這本書的內容比較貼近基礎,對於剛掌握C++基礎的人會有不少的提高。不過書中還是涉及了不少C++的高級特性,閱讀起來需要查閱相關的資料。書中給出了大量的示例和代碼來說明具體規則的原理,我按照書中給出的標題將每個條目的關鍵內容整理如下。一方面是保留一份讀書筆記,另一方面也是為了方便日后查閱方便。當然,如果不能從簡單摘要的內容回憶起具體信息,到時再查書也不遲。同時也期望大家能從中找到自己沒有注意的知識點,有所提高,大牛勿噴~ ☺。
(一)、讓自己習慣C++
一、C++語言聯邦
多重范型編程語言:過程式、面向對象式、函數式編程、泛型編程、模板元編程。
二、const、enum、inline替換#define
const:代替宏變量有助於編譯器理解;
enum:enum hack,更像define,不消耗內存,無法取地址;
inline:宏函數盡量用inline代替。
三、const
const返回值:避免(a*b)=c的錯誤;
const參數:傳遞指向常量的引用;
const成員函數:允許const屬性的重載。
四、對象使用前初始化
構造函數成員初始化列表;
使用時調用,單例模式,多線程不安全。
(二)、構造/析構/賦值運算
五、C++默認編寫的函數
默認構造、復制構造、析構、賦值運算符。
六、拒絕自動生成的函數
私有化拷貝構造和賦值運算符;
私有繼承UnCopyable手工類。
七、多態基類聲明虛析構函數
(不)具有多態性質基類(不)需要虛析構函數;
八、不讓異常逃出析構
異常時終止或者吞下;
將可能拋出異常的代碼提供給用戶管理;
九、不在構造和析構中調用虛函數
調用后僅僅是自身的虛函數,而非子類;
需要子類構造信息解決方案:子類使用靜態函數構造基類的參數。
十、operator=返回*this的引用
允許連續賦值。
十一、operator=處理自我賦值
注意資源的釋放順序。
十二、復制對象要面面俱到
不要丟失基類的成員的復制。
(三)、資源管理
十三、對象管理資源
構造函數獲得資源,析構函數釋放資源;
使用智能指針封裝:tr1::shared_ptr和auto_ptr。
十四、資源管理中小心copying
互斥鎖加解鎖的對象禁止復制;
引用計數法,tr1::shared_ptr<Mutex> mutex_ptr(pm,unlock),含有刪除器的指針。
十五、資源管理類提供原始資源訪問
原始資源獲取;
隱式轉換——類型轉換函數。
十六、new-delete同型成對
[]的出現與否要對應起來,即使使用了typedef重命名了數組類型。
十七、獨立成句的new對象放入智能指針
將new對象轉換為智能指針作為參數,可能會被編譯器結合其他參數調整順序,造成內存泄漏。、
(四)、設計與聲明
十八、讓接口易用而不誤用
類型一致性;
shared_ptr防范跨DLL錯誤。
十九、設計class猶如設計type
12條准則。
二十、常引用參數代替值傳遞
前者高效,但是對於內置類型除外。
二十一、需要返回對象時候不要返回引用
棧、堆、靜態對象都不要作為引用返回。
二十二、成員變量聲明為private
兩種訪問權限:private和others;
protected並不比public封裝性好。
二十三、用非成員函數和非友元函數替換成員函數
封裝強度和改變強度成反比,因為只影響有限的用戶;
類外訪問函數封裝性好於累內成員函數的封裝性,不增加累內私有數據的訪問函數的數量;
二十四、參數需要類型轉換應使用非成員函數
針對二元運算符重載。
二十五、沒有異常的swap函數
類外構造特化的swap函數;
不要在swap的時候產生異常。
(五)、實現
二十六、延后變量定義式
不要提前定義,直到使用改變量的前一刻為之;
針對循環內的對象需要根據構造析構與賦值的成本,以及可維護性進行權衡。
二十七、少做轉型操作
Base(*this).virFun()只會影響對象的基類部分的數據副本,不會影響對象本身,如果使用指針類型轉換則會無窮遞歸,去掉虛屬性則消除類似問題;
用虛函數的特性代替dynamic_cast;
盡量使用C++風格的轉型。
二十八、避免返回對象內部數據的引用或指針
破壞了封裝型;
函數返回對象析構導致空指針。
二十九、異常安全的努力
對象管理資源;
copy-swap實現技術;
異常安全性取決於最弱安全保證的代碼。
三十、inline里里外外
隱式:累內直接定義成(友)員函數,顯式:inline關鍵字;
拒絕:復雜、虛函數、函數指針調用、模板、構造析構函數、影響動態連接或升級、對調試器的挑戰(禁用)。
三十一、降低文件間編譯依存關系
能使用引用和指針完成的不使用對象、用class聲明代替定義,並提供不同的頭文件——程序庫文件和類定義頭文件;
handle class和interface class解除了接口與實現的耦合關系。
(六)、繼承與面向對象設計
三十二、確定public繼承塑膜出is-a關系
適用於基類的事情也適用於子類。
三十三、避免遮掩繼承來的名稱
基類的重載函數一旦在子類被重寫后,其他的同名函數無法訪問。
三十四、區分接口繼承和實現繼承
接口聲明為純虛函數,實現單獨列出;
純虛函數指定接口繼承,虛函數指定接口和默認實現,一般函數指定接口和強制實現。
三十五、考慮虛函數以外的選擇
私有虛函數在父類被調用的時候自動多態,基本保留何時調用的權力,子類擁有修改功能的權力;
function函數指針對象使得函數指針更加靈活;
古典策略模式:
使得不同的功能通過繼承HealthCalcFunc改變。
三十六、絕不定義繼承的非虛函數
重修繼承的非虛函數導致函數的訪問由指向對象的指針或引用類型決定。
三十七、絕不定義繼承的默認參數值
重載的虛函數的默認參數來自於基類;
將默認參數函數聲明為普通成員函數,調用私有的虛函數即可。
三十八、用復合塑膜出has-a和實現關系
has-a:對象的包含關系;
實現:對象對另一個對象進行具體特化。
三十九、審慎使用private繼承
私有繼承表達的是實現關系,子類使用父類提供的接口,但是不繼承;
能用復合不用私有繼承;
如何實現final字段:
這樣Widget的子類就不會修改onTick函數了,將內部類移出,換做聲明可以降低耦合;
private繼承的空基類的大小實際為0,一般對象大小不能為0;
需要基類protected成員或者重寫虛函數時候可以考慮使用private繼承。
四十、審慎使用多重繼承
使用虛基類導致速度變慢;
多重繼承中使用公有繼承繼承接口,私有繼承完成實現關系。
(七)、模板與泛型編程
四十一、隱式接口與編譯多態
class是顯示接口——函數簽名,運行多態——虛函數;
template是隱式接口——有效表達式,編譯多態——模板具體化與函數重載解析。
四十二、typename雙重含義
模板聲明中與class沒有任何區別;
嵌套從屬類型的顯式指定,不能出現在基類列表和初始化列表中;
四十三、處理模板化基類名稱
繼承模板化基類的名稱不能像繼承一樣使用:通過this->名字修飾、using 基類<T>::名字、或者基類<T>::名字一共三種修飾方式。第三種導致虛函數功能失效。
四十四、參數無關代碼抽離模板
將與模板無關的非類型參數轉移到類內;
盡量降低與模板無關的類型參數的膨脹度。
四十五、運用成員函數模板接受兼容類型
成員函數使用函數模板兼容更多類型;
函數模板聲明后的copy構造和編譯器生成的並不同,需要單獨處理。
四十六、類型轉換時為模板定義非成員函數
對於模板化的類要支持雙操作運算符重載,首先必須是非成員函數,另外為了能讓模板具體化必須將函數定在類體內部,因此只能將之聲明為友元類型。(並非模板類內的友元函數必須類內定義)。
四十七、使用traits 類表現類型信息
STL五大迭代器:
1.輸入迭代器:向前,一次一步,只讀一次,istream_iterator。
2.輸出迭代器:向前,一次一步,只寫一次, ostream_iterator。
3.前向迭代器:向前,一次一步,可讀可寫多次,單向列表。
4.雙向迭代器:向前向后,一次一步,可讀可寫多次,list、set、map。
5.隨機迭代器:向前向后,一次多步,可讀可寫多次,vector、deque、string。
實現迭代器累加操作時候需要根據迭代器類型執行不同的操作方式,這種判斷屬於編譯時期的判斷,不應該使用if語句!
可以根據iterator_traits提供的類別標簽區分迭代器類型,類別標簽是空結構體類型,將標簽作為函數參數,可以保證編譯器能在編譯時期對類型進行檢查。
現在就可以把doAdvance封裝起來自動完成編譯期類型判斷。
四十八、模板元編程
讓某些事情變得容易可能,將某些工作從運行期轉移到編譯期;
分支——借由模板特化實現;
循環——借由遞歸完成;
優點:保證度量單位的正確、優化矩陣運算生成客戶定制設計模式實現品;
避免了生成某些特殊類型不適合的代碼。
(八)、定制new和delete
四十九、new-handler行為
set_new_handler指定內存分配失敗時調用的函數。
五十、new、delete合理替換時機
改善性能,內存對齊,heap錯誤調試,收集heap信息。
五十一、new、delete固守常規
new含有無限循環分配內存,無法分配調用new-handler,處理0字節和超額申請;
delete處理null指針和超額申請。
五十二、寫了placement new就要寫placement delete
placement new在已有的緩沖區內申請對象;
不要掩蓋已有的版本。
(九)、雜項
五十三、不要忽視警告
嚴肅對待警告信息;
不過度依賴警告信息。
五十四、熟悉TR1標准庫
智能指針、Boost庫。
五十五、熟悉Boost
社群、網站;
TR1組件實現品。