C++編程優化心得(持續更新)


1. 對齊原則。比如64位總線,每次尋址讀取8B。編程時注意變量地址,盡量消耗總線最少的尋址次數。堆內存申請時,系統嚴格按照對齊原則分配,故而使用時候也盡量不要跨尋址邊界。

2. 需要的時候,可為了效率拷貝代碼,雖然增加了代碼體積,但這是值得的。尤其是for循環,若次數比較少,拆開亦無妨。

3. 位運算中,-1右移,左邊補1,故仍為-1;-1左移,右邊補0,故不再為-1。

4. 每次申請的堆內存,最好初始化,里面是垃圾數據,而並非為空。

5. 項目開發中,往往一個引擎對外暴露的是一個純虛類,而其接口就是這個類的**指針變量。

6. 程序邏輯,重在語義。不能為代碼的過分簡單而減少函數的設計。

7. *&表示對指針的引用。

8. 類的靜態方法不可調用其非靜態方法,亦不可調用非靜態成員變量。

9. 多文件編程時,頭文件不可相互包含。

10. 頭文件里盡量不要使用using namespace std;

11. static成員定義要放在cpp文件里面,而不是頭文件里。

12. 純虛類盡量不要延續兩層以上。

13. include引用盡量都放在cpp文件里。

14. 子類繼承父類,不可在構造函數里初始化父類並未在構造函數里初始化的成員,也就是說,子類構造函數里能初始化的成員,只有自己本身的和父類構造函數里的。

15. 項目開發中,對於一些依賴本地環境的參數,要寫專門的配置文件,比如服務器地址。

16. 頭文件里只聲明,不定義。在頭文件中,全局變量聲明,必須加extern修飾;靜態成員變量聲明放在頭文件,定義放在cpp文件,若是普通靜態變量,最好聲明和定義放在cpp,因為static作用域限於單文件,放在cpp里只對本文件可見,放在頭文件會被所有引用該頭文件的cpp拷貝一份完全相同的變量。

17. linux下,進行文件操作時,文件路徑要采用絕對路徑(相對路徑很多時候會出bug),文件指針要對其返回值作判斷,防止空指針。

18. debug狀態下使用assert是極好的,不過記得發布版本前在#include <cassert>前加上#define NDEBUG,assert語句會被NDEBUG所影響。這里多嘴一句,錯誤與異常是不同的,異常是不可避免,在發布版本里不可或缺的,故而assert不能用於處理異常。注:在加上#define NDEBUG后,不論是調試還是運行,assert語句都會被直接忽略,故而平時開發時把#define NDEBUG注釋掉,發布時再啟用它。

19. 面向對象編程:可維護,可復用,可擴展,靈活性好。

20. 頻繁使用的代碼里,盡量少使用容器,因為其創建和回收的開銷很大。

21. 字符串拼接效率:經過測試(http://bbs.csdn.net/topics/360000434和我自己項目中的實驗),memcpy效率最高,string類的+=效率特別高,足以滿足日常所需,而strcat效率很差,append也不快。

22. 基類中的虛函數要么實現,要么是純虛函數(絕對不允許聲明不實現,也不純虛)。

23. 在C++的類中,普通成員函數不能作為pthread_create的線程函數,如果要作為pthread_create中的線程函數,必須是static。

24. 當多個線程訪問同一個類靜態方法時,若該方法里只操作棧上數據,則無妨,因為線程的棧是獨立的;若該方法操作了非棧上的數據(比如堆、全局變量等),則需要互斥鎖。

25. 內聯函數,定義體要放在頭文件,以保證每一個引用該頭文件的cpp里都是完全相同的拷貝;inline關鍵字置於定義前,不必放在聲明前;若定義在類內部,可不需要inline關鍵字。

26. vector執行clear時,會自動調用元素(如果是類的話)的析構函數。

27. 編程時,對變量(尤其是全局性質的變量或類)命名,要用解釋性的,而不能用隨意的j1,i1,n,m等名稱,容易與庫里的變量沖突。

28. 定義宏時,盡量多用整數,少用-1,-2之類,容易受uint和int不統一帶來的困擾。

29. 函數形參采用默認值時,要寫在聲明里,而不寫定義里,這樣方便調用其頭文件的cpp看得到默認值。

31. utf-8 中文編碼 三個字節表示一個漢字

32. 項目開發時,使用條件編譯:

#define DEBUG
main()
{
#ifdef DEBUG
    printf("Debugging\n");
#else
    printf("Not debugging\n");
#endif
    printf("Running\n");
}

發布版本時,注釋掉第一行。這種方式要比開大量注釋來得方便。

33. 關於c字符數組,需要注意一個初始化問題:

(1) char str[10]="";
(2) char str[10]={'\0'};
(3) char str[10]; str[0]='\0';

前兩者的意義在於str的每個元素都初始化為'\0',第三者僅僅初始化第一個元素。當數組長度很大時,前兩者時間開銷極大。故而,有些不必要的時候,不要如此初始化。

34. 判斷一個字符是否為數字:

頭文件:#include <ctype.h>
定義函數:int isdigit(int c);
函數說明:檢查參數 c 是否為阿拉伯數字0 到9。
返回值:若參數c 為阿拉伯數字,則返回true,否則返回null(0)。
附加說明:此為宏定義,非真正函數。

#include <ctype.h>
main(){
    char str[] = "123@#FDsP[e?";
    int i;
    for(i = 0; str[i] != 0; i++)
        if(isdigit(str[i]))
            printf("%c is an digit character\n", str[i]);
}

35. 在類里聲明靜態常量,尤其是數組定義的時候,如static const *str = "sdfsssf", 要在const前加上constexpr修飾,可以在編譯器就將“sdfsssf”賦值給str,達到類似宏的效果。

36. std::string::find_last_of("/\\") 這里的"/\\"指的是'/'或'\',在搜索字符時用得到。

37. 項目里c字符串傳遞,多采用首地址+長度的方式,避免0x0存在導致的異常; 線程數要合適,大致為cpu總核數兩倍以內為佳,線程間切換會一定程度上消耗程序性能。

  有一個陷阱是在c字符串轉string類型時,c字符串里如有0,轉化時用strlen取長度就會出錯。故而,c串表示盡量維護一個len來記錄長度,而不是通過結尾0來判別。另外,strlen效率低且不安全,少用。

38. 靜態函數的實現寫在h文件里;盡量把h文件里的函數實現前都加上inline,不論其復雜度,避免被多文件引用而引起重復定義錯誤。

39. 靜態成員變量必須在類外進行初始化。如果是復雜類型,比如容器,也要在類外定義,如std::vector<xx *> hj::sm_tr;

40. 編程時,一般結構體里的堆內存由內存池管理申請或釋放,或者stl里使用這些結構體作為元素時,使用其指針,而不是實例。因為stl里內存申請或釋放,會調用其元素的構造和析構,這里會有陷阱。

41. 使用set、map時,有一個陷阱,就是[]操作符。當使用這個操作符時,如果[x]里的x並不在set或map里,則stl會自動生成一個x元素,這樣使得stl容器內容改變,如果開發者忽略了這點,后果可能無法預期。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM