????????本文章屬于專欄《業界Cpp進階建議整理》
????????本文列出《More Effective C++》的1-10條的個人理解的極精簡版本。
- 1、仔細區分pointers和references
- 使用引用的情況:
- 一旦代表的該對象就不能改變,應該選擇reference(優勢是使用時不需要判是否空)。
- 實現一個操作符時,為了方便讀寫,返回引用
- 其他任何時候,用pointers
- 使用引用的情況:
- 2、最好使用C++轉型操作符
- 個人見解:在性能要求不高的地方盡量使用C++轉型操作符,以降低閱讀、維護成本。不在極高頻調用的代碼中使用,以降低機器成本
- 3、絕對不要以多態方式處理數組(std::array)
- 核心是不要在std::array中存派生類對象,然后傳給處理array[基類]的函數。因為傳入后,在以下兩個場景使用是有問題的
- array遍歷元素,是按照指針類型做間隔(派生類比基類大,會導致偏移錯誤)
- 通過基類指針刪除一個派生類構成的數組,在C++中是未定義的。
- 常用的正確的做法是用vector,存儲基類指針(派生類對象永遠不要直接賦值給基類對象,會導致部分覆蓋)
- 個人見解:在業務代碼中放棄使用std::array,固定長度的數組意味著一旦改變就意味著重啟。且在大部分場景性能收益不大
- 4、非必要不提供默認構造函數(不要參數的,系統默認創建的構造函數)
- 《more effective cpp》作者認為兩種情況下是必要的
- A a[10],放在數組中,沒有辦法進行傳參初始化(不過這個場景并不常用,即使用,也是低頻場景,這個時候用,使用vector + for循環初始化,也是夠用的)
- 基類沒有默認初始化函數時,派生類需要在構建時,需要顯示初始化基類
- 個人理解:
- 同上一條類似,放棄a[10]這種原始數組,使用std::vector。
- 做為基類,有一個默認構造函數,可以節省一些代碼,特別是繼承層數比較多的情況
- 《more effective cpp》作者認為兩種情況下是必要的
- 5、不要提供轉換函數
- 單自變量的構造函數和隱式轉換操作符(如operator double()),會提供隱式轉換的功能
- 盡量不要提供隱式轉換的功能,如在cout << a時,如果a本身沒有寫<<操作符,但是a能隱式轉換類型,則會先轉換類型,再調用該類型的 <<。這類操作很容易出現不符合預期的結果。
- 用explicit來禁止,單變量的構造函數的隱式轉換
- 6、區別++、--的前置和后置的區別
- A& operator++() 返回自身。【前置++i】
- const A operator++(int) 返回一個當前對象的copy,然后對自身對象+1。【后置i++】
- 個人見解:在循環時,永遠使用前置。在業務邏輯中,不管是前置還是后置,都單獨寫一行,性能一樣,且代碼更易讀,放棄if(fun(a++))這種寫法。改為if(run(a)) & a++
- 7、千萬不要重載 && ,|| 和,
- 實際用的時候,期望 &&前面失敗后面就不執行,但是重載的時候做不到
- 8、了解各種不同意義的new和delete
- new
- new operator:
- 說明:語言內構建,不能被改變意義,總是做相同的事:1、分配足夠的內存 2、調用構造函數給分配的內存設定初值。可以改變實現方式,但是不能改變函數步驟和語義
- 例子: A* a = new A();
- operator new:
- 說明:這是一個函數,可以被重寫或者重載,它除了內存分配,不會做任何事情,形式為:void* operator new(size_t size);
- 例子: void* rawMemory = operator new(sizeof(A));
- placement new
- 將已有對象,構建在指定內存地址上
- 例子:void *buffer = operator new(sizeof(int)); new (buffer) A a;
- 這里獲取buffer時,調用一個 void* operator new(size_t)函數,得到一個內存空間
- 然后調用void operator new(size_t, void* local) {return loacl},并在該函數返回的指針上面調用構造函數
- new operator:
- delete
- 當使用placement new時,要先調用析構函數,a->~A(); 然后再調用自己寫的函數,釋放內存,畢竟只有自己知道內存空間是如何創建的
- 個人見解:放棄為了性能overwrite new/delete,使用tcmalloc或者jecmalloc。參考我的文章《c++的高性能內存管理庫tcmalloc和jemalloc》
- new
- 9、利用destructors避免泄漏資源
- 本質就是把heap指針,放到棧上對象,保證釋放時,內存也會被釋放。如智能指針
- 10、防止constructor泄漏資源
- 本質相同,就是用stack對象管理heap對象,也就是對象的所有heap的成員對象,都用智能指針管理