優化相關
- 使用靈活的、動態分配的資料,不要使用固定大小多陣列;
-
優先使用線性演算法或者盡可能快的演算法:
- push_back 散串列查詢:O(1)
- set/map lower_bound/upper_bound: O(logN)
- vector::insert for_each O(N)
-
盡可能避免劣于線性復雜性的演算法,永遠不要使用指數復雜性的演算法;
- 不要進行不成熟的優化:
- 可以用通過參考傳遞的時候,卻定義了通過值傳遞的方式傳遞引數;
- 可以使用前綴++、--運算的時候,卻使用了后綴的方式;
- 建構式中使用賦值操作而非初始化串列
并發編程
- 盡量減少全域和共享資料
避免使用名字空間作用域中具有外部連接的資料或者作為靜態類成員的資料,如果不得不用,一定要對其仔細進行初始化,在不同編譯單位中這種物件的初始化順序是未定義的,為此需要高度注意;另外,名字空間作用域中的物件、靜態資料成員物件或者跨執行緒(行程)共享的物件會減少并行性,往往是產生性能和可伸縮性瓶勁的原因,
例外情況: cin/cout/cerr 比較特殊: cout << "hello world" 等價于
(cout, "hello world");
-
使用C++撰寫可靠的多執行緒的代碼,認真考慮下面的建議:
- 參考目標平臺的檔案,了解改平臺的同步原語,比如原子操作、記憶體屏障
- 最好將平臺的原語用自己設計的抽象包裝起來:比如使用pthread;
- 確保正在使用的型別在多執行緒程式中使用是安全的:
保證非共享的物件獨立;
確定在不同執行緒中使用該型別的同一個物件到底是不是需要加鎖、考慮最合適的加鎖粒度;
-
如果撰寫可能用于多執行緒的型別,必須完成兩項任務:
- 確保不同執行緒可以不加鎖地使用該型別的不同物件;
- 必須明確且提供不同執行緒使用該型別的同一個物件需要做的操作:
是否需要考慮外部加鎖: 呼叫者自己負責加鎖
是否需要內部加鎖:為每個公有成員函式的操作加鎖,比如生產者-消費者模型通常使用內部加鎖,需要考慮:
第一、 確認該型別的物件總是要被跨執行緒共享;
第二、型別介面的設計應該有利于粗粒度、自給自足的操作,如果內部的鎖加得很合適,那么對呼叫者而言是透明無感的,
第三、不變物件(只讀的、常量字串)不需加鎖,
- 確保資源為物件所擁有,使用顯式的RAII和智能指標
- 使用RAII時,小心復制建構式和賦值建構式;
- 使用智能指標而非原始指標來保存動態分配的資源:shared_ptr<T *>
- 應該顯式地執行資源分配(比如new);
- 馬上將申請分配的資源賦予給管理物件:
比如:
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);
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/82046.html
標籤:C++
上一篇:各種排序(二)
下一篇:如何申請騰訊地圖用戶Key
