用c++開發一款商業產品,須要哪些規範

圖片描述

最近開始接手項目組的開發管理工做,項目組開發的產品一期功能基本開發完成,進入內部測試及小渠道發佈階段,然而產品的穩定性還存在很大問題。c++

先作一下背景介紹,項目組開發的是一款面向C端的互聯剛產品,運行操做系統爲windows。整個項目使用c++開發,整體代碼量大概在數十萬行。算法

c++是一門很複雜的語言,有不少強大的特性,然而當用其開發一款商業產品時,這些特性可能會帶來麻煩。因此當設計c++的使用規範時,更多的是對其作減法。windows

本文的規範針對VC++開發環境,開發工具爲Visual Studio。多線程

文件系統目錄規範

一款完整的商業產品開發一般會涉及到不少模塊,這其中包括可執行程序(.exe),項目組開發的庫(靜態庫或動態庫),第三方的庫(靜態庫或動態庫),測試程序,這麼多的模塊和代碼,須要一個良好組織的目錄結夠。
這裏假設項目名稱爲XXProject異步

  • XXProject函數

    • XXProject.sln工具

    • Bin開發工具

      • Debug測試

      • Release編碼

    • TestBin

      • Debug

      • Release

    • Src

    • Document

其中Bin存放須要發佈的可執行程序,TestBin存放測試程序的可執行文件,Src存放項目的工程文件和源代碼,Document存放項目相關的開發文檔(如項目說明,代碼規範等)。

接下來假設項目包括以下工程:XXMain(發佈的主程序),XXUpdate(升級程序),XXSdk(本身開發的基礎庫),XXThird(第三方庫), XXTest(測試程序)

  • Src

    • XXMain

      • XXMain.vcxproy

      • code文件

    • XXUpdate

      • XXUpdate.vcxproy

      • code文件

    • XXTest

      • XXTest.vcxproy

      • code文件

    • XXSdk

      • XXSdk.vcxproy

      • code文件

    • ThirdLib

      • XXThird

    • Lib

      • Debug

      • Release

    • Include
      Lib庫用來存放靜態庫,動態庫的.a文件,Include用來存放公共頭文件,ThirdLib用來存放第三方庫。

解決方案目錄規範

解決方案目錄是VS開發工具提供的邏輯上組織項目的方式,與物理文件系統並不存在對應關係。
仍然假設項目包含上述項目和模塊。

  • Solution (解決方案)

    • Application (解決方案文件夾)

      • XXMain (工程)

      • XXUpdate (工程)

    • Test (解決方案文件夾)

      • XXTest (工程)

    • Library (解決方案文件夾)

      • XXSdk

    • ThirdLibrary(解決方案文件夾)

      • XXThird

    • Public (解決方案文件夾)

      • 公共頭文件

代碼編寫規範

1:禁用全局變量

全局變量會帶來晦澀的依賴問題

2:禁用goto指令

goto指令的代碼難以閱讀和維護

3:禁用異常機制

c++的異常機制有不少缺陷且複雜

4:用struct封裝數據,使用class定義對象

C++中class和struct幾乎沒有區別,在規範中進行語義的區分

5:struct和class必須顯示包含構造函數
6:除非特殊狀況,老是將析構函數定義爲虛函數

方便繼承時的資源釋放

7:不要在構造函數中執行復雜操做,推薦加入init函數用於初始化操做

構造函數沒有返回值,難以反饋錯誤

8:不要在構造函數中調用虛函數

構造函數中的虛函數不會重定向到子類。

9:慎用繼承

相比對象組合,繼承帶來更強的依賴,推薦使用接口繼承而不是對象繼承

10:禁用多重繼承(接口繼承除外)

多重繼承一般表明很差的設計

11:慎用運算符重載

運算符重載會混淆代碼的語義,應只在不會形成混淆時使用

12:將成員設置爲私有並提供訪問函數

封裝是下降代碼耦合的有力武器

13:將同一訪問權限的成員定義在一塊兒

能夠按照public,protect,private順序進行組織

14:避免出現大而全的類

當一個類的代碼超過1000行,應有所警戒,超過2000行,則應考慮拆分(行數不包括註釋)

15:頭文件應包含它所須要的頭文件

這樣能夠保證cpp文件引入該頭文件後不須要包含其它頭文件

16:合理的組織引入的頭文件,不要重複引入,不要引入沒必要要的頭文件

能夠以系統頭文件,第三方庫頭文件,項目組庫頭文件,本程序頭文件來組合,不一樣類型頭文件之間用空格隔開

17:頭文件使用#define宏來避免多重包含

pragma once 指令只有VC編譯器能識別

18:容許合理的使用友元特性

19:使用引用傳遞對象類型參數, 對於不須要改變的參數加入const修飾符

引用傳遞能夠避免對象拷貝

20:函數應該進參在前,出參在後

21:使用明確的返回值指示函數的運行結果,而不是用返回的內容來指示結果

推薦: int GetDeviceName(string& deviceName);
不推薦: string GetDeviceName()

22:聲明基本類型變量後當即賦值

正確 int nCount = 0; bool bSuc = false; 錯誤 int nCount; bool bsuc;

23:使用內聯,枚舉,常量來代替宏

宏的使用有不少弊端,應儘可能避免

24:使用singleton模式代替靜態類

相比靜態類,singleton模式能夠更好地控制初始化時機。

25:使用share_ptr來管理指針

指針和管理在複雜項目中十分困難,使用智能指針是不二選擇

26:使用weak_ptr來處理循環引用
27:明確對象或資源的生存週期

明確對象的生存週期一般表明着良好的設計

28:合理的使用縮進,空格

最重要的是保持風格的統一,自動生成的代碼可能會打破這種統一,應該靈活設計規則

29:合理使用typedef縮減類型的長度,合理使用auto

使用stl時常常會致使過長的類型,合理使用auto能夠有效減小代碼長度

命名規則

因爲是在VC環境下開發,沿用微軟的命名駝峯命名法

選擇哪一種命名方式實際上不是很重要,最重要的是保持統一

  • 代碼文件: DeviceMgr.h, DeviceMgr.cpp

  • 解決方案目錄: NetLibrary

  • 工程篩選器: DataModel

  • 類:CDeviceMgr

  • 結構體: DeviceInfo

  • 變量: listDevice

  • 類成員: m_deviceName

  • 函數: GetName; GetDeviceName;

  • 表明bool含義的變量: 都以b開頭,如:bOk, bSafe

  • 表明整數含義的變量: i表示符號整數,n表示無符號整數

  • 避免無心義的變量名和縮寫: 如 x,dn(deviceName)等

註釋規則

  • 文件註釋:註明文件做者,聯繫方式,文件代碼做用,重大修改記錄等

  • 類註釋:說明類的做用,使用限制等等

  • 函數註釋: 儘可能依靠意義明確的函數命名而不是依靠註釋,說明函數的使用限制,對於意義不明確的參數加以說明

  • 變量註釋:儘可能依靠意義明確的變量命名而不是依靠註釋,特殊狀況。

  • 實現註釋: 對於使用了很是規技巧,或複雜算法,或很複雜的業務邏輯部分要加入註釋說明

原則: 註釋應風格統一,簡短而意義明確,最終目的是有效幫助其它人閱讀和理解代碼的目的

日誌

日誌的打印十分重要,是產品發生問題時重要的參考依據

  • 日誌的打印要儘可能詳盡,合理劃分日誌等級,通常爲Fatal, ERROR, WARNING, DEBUG, INFO

  • 統一使用unicode(utf-16)編碼來輸出日誌

  • 提供異步打印日誌的接口

  • 提供按期清理日誌的機制

  • 在發佈版中將日誌等級設置爲ERROR或更高,提供配置文件供調整日誌等級

一些其它規則

  • 避免大而全的類(代碼控制在1000行之內)

  • 避免過長的函數(代碼控制在200行之內)

  • 避免深層的嵌套(不要超過3層)

  • 使用do-while-break技巧來避免重複寫釋放資源的代碼

  • 儘可能使用RALL技巧來釋放資源

  • 當函數或代碼廢棄時,應與標註,最好將其註釋掉並按期清理

線程和鎖

複雜的項目確定會涉及到多線程開發,而開發多線程程序是十分困難的。據咱們統計,項目組產品有70%左右的崩潰和bug和線程有關。

將線程模塊獨立出來,交給項目最有經驗的開發人員管理和維護,對外暴露抽象接口,屏蔽線程的概念。

強制使用RALL技術來使用鎖

未盡本文並無涉及到C++規範的全部方面,歡迎討論和補充

相關文章
相關標籤/搜索