C++的一些編程規範

新規範的目標:

  • 讓代碼排錯更加簡單
  • 程序員專心於業務邏輯
  • 將一些錯誤交給編譯器處理
  • 提升代碼可維護性
  • 逐步實現插件化

編碼

  • 使用array(QT下用QVarLengthArray)代替和vector代替原生數組,除非與外部庫交互,不然不要直接操做內存(即暴露data的接口)程序員

    關於array和vector初始化麻煩的問題,在VS2010下使用boost::assign庫,在VS2015下則使用list initial的語法算法

    使用array和vector代替原生數組之後,能夠很好找到越界的地方數據庫

  • 儘可能不要直接操做內存, 若是須要使用內存和字符串操做,儘可能使用memset_s, memcpy_s,儘可能使用_s結尾的函數json

    http://en.cppreference.com/w/c/string/byte數組

    若是須要初始化數組,使用int a[COUNT] = {0}這種語法(但實際上儘可能不要直接使用原生數組)網絡

  • 在進行memory操做的時候,須要使用is_pod驗證下變量類型是否pod類型數據結構

  • 使用STL的算法代替手寫的算法,日常用到的算法STL裏面或者QT的算法模塊裏面都有多線程

    http://en.cppreference.com/w/cpp/algorithm架構

  • 構造函數必定要初始化C原生類型的數據成員函數

  • 使用C++風格的轉換,不要用C語言方式的轉換

    dynamic_cast,當繼承樹不同的時候,編譯器將會報錯,或者轉換失敗,原生的C語言編譯正確而且轉換正確

    static_cast,會有轉換類型檢查,好比子類往父類強轉,編譯期檢查

  • 使用QVariant代替void*

    當進行強轉錯誤的時候,QVariant能直接返回錯誤的數值

  • 使用強枚舉

    便於查看代碼

    若是傳入錯誤,能夠直接讓編譯器報錯

  • 編寫測試,系統檢測架構圖,而後 將測試用例自動化

  • 分離數據和界面

  • 經常使用的宏定義,放在Global裏面,相似於qt_global文件

    IOCEAN裏面常常會有重複的宏定義,好比PI,好比無效的HDG,須要防止這種狀況

  • 多用const

    const的類成員函數,告訴使用者這個函數將不會對類成員進行改變,在寫代碼若是有改變,也能直接報錯

    const的參數

    const的引用參數

    在計算出一些臨時的參數後,若是肯定這個參數不會再改變了,也建議用const

  • 使用Q_ASSERT, assert, static_assert斷言處理邏輯上不可能出現的狀況

    若是已經使用Q_ASSERT,表示這種狀況下不須要測試

    在發送網絡的數據的時候,有時候發送的是純二進制數據,可是後續用戶可能會在這個數據加入非POD數據,可使用static_assert( std::is_pod<>::value) 來確保這個結構體是純二進制數據

  • 字符串和數據結構庫統一使用QT的庫,好比QLIST,QVector,而非std::list,std::vector

    爲了防止混用

    與QT庫比較好結合

  • 信號鏈接使用QT5的新語法

資源管理

  • 使用scoped_pointer和shared_pointer來代替原始指針

    專一業務編寫,而非內存管理以及排錯

    便於調試,若是是局部變量的指針,在release會直接被優化成地址,沒法顯示信息,若是是shared_pointer或者scoped_pointer則不會

  • 全部建立的線程,都要設置名稱,方便查詢線程的用處

  • 資源應該遵循誰申請誰釋放的原則,不該該把一個資源胡亂傳遞(將會致使最後資源不知道誰釋放誰持有)

    • 若是資源須要轉移,儘可能使用MOVE來進行轉移,而後用RAII來釋放
  • CPP裏面的模塊變量使用static const而不是隻有const聲明

  • 使用static const代替宏定義

代碼結構

  • 記錄log,log不只僅是開發的時候調試使用,更是在用戶機子上分析錯誤的重要工具,如今咱們大部分的log都是維持在debug級別,應該要多編寫warning和error級別的log

    因爲不少狀況下,一些錯誤的狀況沒法復現,也沒法分析,特別在部署到用戶機子上之後,很難到現場排查

    一開始不必定要記錄log,根據本身的經驗判斷是否須要log,可是隨着開發進度的增長,會出現一些莫名其妙的錯誤,好比網絡不穩定,內存不穩定致使問題,排查完問題後,在發生問題的根源記錄下log

    1. 有一個問題,常常會掉線,由於網絡有時候波動會比較大,寫數據庫會很慢,這個時候若是新客戶端連上去後會發送全部的數據,將會致使心跳包處理不及時,客戶端會主動斷開,排查完緣由後,在初始化發送數據的地方編寫一段代碼,當初始化超過必定的時間後,將會記錄一個warning,下次發生這種狀況,直接經過log來排查分析

    2. 有時候一些模塊由於須要排隊處理數據,可是數據處理不即時,致使數據一直存儲在buffer裏面,可是按照正常狀況下,不該該發生這種狀況。排查完問題之後,應該在插入buffer的地方寫一個判斷代碼,當buffer大於多少後,給出一個warning

  • 底層數據管理類不要直接暴露內部的狀況,而且將對底層數據操做的算法提取出來寫在管理類裏面,而不是你們都寫一個相同的算法

    在代碼重構階段,一旦底層數據直接暴露,那麼將會很難修改

    一旦代碼有相關聯的模塊,這種方式比較好處理,好比刪除元素,須要把相關聯的數據都刪除掉,若是沒有把deleteTarget封裝成一個接口,那麼須要查找全部相關聯的代碼,把這個業務的代碼再寫一遍

    防止大部分人寫了相同的代碼

  • 全部數據只有一份,包括內存裏面的數據和網絡消息,如今一個數據結構常常定義了2-3份數據,包括內存裏面的,序列化成網絡消息的

  • 組合,繼承與接口設計

    繼承要保證是一個is-a的類型,即保證一樣的邏輯操做能夠用在同一個接口上面,而不須要進行大量的轉換,若是邏輯操做出現大量的類型轉換,考慮是否繼承出現了問題

  • 信號

    將業務組合成一個函數,單獨的功能寫成一個單獨的模塊,而後在一個函數裏面將這些業務組合起來

  • 若是有大量相同的邏輯代碼,考慮是否能夠提取成一個函數或者模板, 特別是當一個邏輯不會增長依賴的時候

  • 若是使用了大量的dynamic_cast,而且有相同邏輯的代碼,考慮是否能夠將這個行爲抽象成一個接口

工程方案

  • 通用的庫弄成一個lib,好比SQL之類的庫

  • 非通用的庫,可是一些項目裏面要用到的,新建一個解決方案,解決方案裏面有一個共用的庫

待議

  • 多線程,openmp, map-reduce模式

- 語義明確的多線程

  • SQL模塊 select(tablename).where("i < 7").and("j > 8").or("x < 2")

  • 使用std::function代理SIGNAL和SLOT的綁定

  • 將不須要製做成索引的數據使用json保存,而不是另外建立一個表而後關聯過去

  • 儘可能使用designer進行佈局

全部人須要瞭解的C++技術

  • C++11

  • RAII

  • Move語義

相關文章
相關標籤/搜索