C++ 進階筆記之一

優化相關

  • 使用靈活的、動態分配的數據,不要使用固定大小多數組;
  • 優先使用線性算法或者儘量快的算法:算法

    1. push_back 散列表查詢:O(1)
    2. set/map lower_bound/upper_bound: O(logN)
    3. vector::insert for_each O(N)
  • 儘量避免劣於線性複雜性的算法,永遠不要使用指數複雜性的算法;編程

  • 不要進行不成熟的優化:
    1. 能夠用經過引用傳遞的時候,卻定義了經過值傳遞的方式傳遞參數;
    2. 可使用前綴++、--運算的時候,卻使用了後綴的方式;
    3. 構造函數中使用賦值操做而非初始化列表

併發編程

  • 儘可能減小全局和共享數據
    避免使用名字空間做用域中具備外部鏈接的數據或者做爲靜態類成員的數據。若是不得不用,必定要對其仔細進行初始化。在不一樣編譯單位中這種對象的初始化順序是未定義的,爲此須要高度注意;另外,名字空間做用域中的對象、靜態數據成員對象或者跨線程(進程)共享的對象會減小並行性,每每是產生性能和可伸縮性瓶勁的緣由。

例外狀況: cin/cout/cerr 比較特殊: cout << "hello world" 等價於
(cout, "hello world");數組

  • 使用C++編寫可靠的多線程的代碼,認真考慮下面的建議:安全

    1. 參考目標平臺的文檔,瞭解改平臺的同步原語,好比原子操做、內存屏障
    2. 最好將平臺的原語用本身設計的抽象包裝起來:好比使用pthread;
    3. 確保正在使用的類型在多線程程序中使用是安全的:
      保證非共享的對象獨立;
      肯定在不一樣線程中使用該類型的同一個對象究竟是不是須要加鎖、考慮最合適的加鎖粒度;
  • 若是編寫可能用於多線程的類型,必須完成兩項任務:多線程

    1. 確保不一樣線程能夠不加鎖地使用該類型的不一樣對象;
    2. 必須明確且提供不一樣線程使用該類型的同一個對象須要作的操做:
      是否須要考慮外部加鎖: 調用者本身負責加鎖
      是否須要內部加鎖:爲每一個公有成員函數的操做加鎖。好比生產者-消費者模型一般使用內部加鎖。須要考慮:
      第1、 確認該類型的對象老是要被跨線程共享;
      第2、類型接口的設計應該有利於粗粒度、自給自足的操做。若是內部的鎖加得很合適,那麼對調用者而言是透明無感的。
      第3、不變對象(只讀的、常量字符串)不需加鎖。
  • 確保資源爲對象所擁有,使用顯式的RAII和智能指針
    1. 使用RAII時,當心複製構造函數和賦值構造函數;
    2. 使用智能指針而非原始指針來保存動態分配的資源:shared_ptr<T *>
    3. 應該顯式地執行資源分配(好比new);
    4. 立刻將申請分配的資源賦予給管理對象:

好比:
void Fun(shared_ptr<Widget> sp1, shared_ptr<Widget> sp2);
Fun(shared_ptr<Widget>(new Widget), shared_ptr<Widget>(new Widget));併發

因爲參數初始化的順序可能由於編譯器的不一樣而改變,一種極端的狀況是:
同時執行了對兩個對象的new 操做的內存分配操做,而後再試圖調用兩個Widget 構造函數。若是這個時候某個構造函數調用拋出異常,另一個對象的內存就永遠沒有機會釋放了。函數

解決方法:絕對不要在一條語句中分配一個以上的資源,應該顯式地執行資源分配(好比new),而後立刻將申請分配的資源賦予給管理對象。例如:性能

shared_ptr<Widget> sp1(new Widget);
shared_ptr<Widget> sp2(new Widget);優化

Fun(sp1, sp2);線程

相關文章
相關標籤/搜索