公司C++規範學習

self發表於2019-06-13

公司C++規範學習

語法部分

  • class和struct關鍵字的選擇:class表示被封裝的使用者自定義型別,不公開定義非靜態資料成員,struct表示資料的簡單集合,只定義用於初始化資料成員的方法。
  • 必須使用建構函式初始化列表顯示初始化直接基類與所有基類型別資料成員。
  • 沒有複製意義的類必須用DISALLOW_COPY_AND_ASSIGN巨集禁止拷貝建構函式和賦值建構函式。
    • DISALLOW_COPY_AND_ASSIGN 巨集就是將複製拷貝函式和賦值操作符宣告為私有變數。
  • 禁止在建構函式中進行可能出錯的複雜操作(比如申請資源),複雜操作用額外的init()函式實現。
  • 顯式初始化能夠使程式碼更清晰、不易錯誤呼叫,還能避免二次賦值造成的效率問題, 單參建構函式儘量加上explicit。
  • 有預設值語義的類必須顯示定義預設建構函式。
  • 沒有預設值語意的類,必須顯式定義其它建構函式或 private 宣告預設建構函式,並不給出實現。
  • 如果型別是可拷貝,一定要同時定義拷貝建構函式和賦值建構函式,如果型別可移動,一定要同時定義移動建構函式和移動賦值函式。
    • 如果使用預設的拷貝和移動操作,要使用=default定義。
    • 如果型別不需要拷貝、移動操作,要使用=delete手段禁用。
    • 向容器新增資料時,優先使用emplace開頭的介面函式。
  • 在極少的情況下,當該類的隱式轉換很有意義時,可以不把單引數建構函式宣告為顯式建構函式,但必須十分小心,並使用文件化註釋說明。
  • 單引數建構函式如果不用explicit關鍵字修飾,則可能被編譯器用來做隱式型別轉換。
  • 有複製意義的類必須顯式給出複製建構函式,並小心指定其行為(淺複製、深複製等)
    • 託管了資源的類,往往是沒有複製意義的。此時應當防止使用者錯誤呼叫而導致資源洩漏、重複釋放的後果。
    • 編譯器預設生成的複製建構函式,對指標資料成員使用淺複製策略,但這種策略常常不是程式設計師希望的。
  • 解構函式:
    • 若類定義了虛擬函式,必須定義虛解構函式。
    • 若類設計為可被繼承的,應該定義公開的虛解構函式或保護的非虛解構函式。
    • [RULE010] (不包括結構)含有指標成員,必須顯式給出解構函式,並小心指定其行為(是否銷燬指標,如何銷燬等).
    • 絕不允許讓異常離開解構函式。
  • 按照 public、protected、private 的順序宣告成員。按照型別、方法、資料成員的順序宣告成員, DISALLOW_COPY_AND_ASSIGN 放在 private 區段的末尾.
  • 不是非常必要的話,避免使用友元: 友元破壞了類的封裝性,增加了類之間的耦合,適宜使用友元的如容器與它的迭代器,類與涉及該類的.
  • 委派和繼承建構函式是由 C++11 引進為了減少建構函式重複程式碼而開發的兩種不同的特性. 通過特殊的初始化列表語法, 委派建構函式允許類的一個建構函式呼叫其他的建構函式.
  • C++11強型別列舉enum class Side
  • 被過載的虛擬函式通過override顯示宣告.
  • 禁止被過載的函式通過final顯示禁止.
  • Lambda表示式:
    • 不使用預設捕獲(包括&, =), 捕獲顯示寫出來.
  • 只在兩種情況下使用右值引用, 一種是定義型別的移動操作函式時, 另一種是定義模板函式實現完美轉發的時候. 除此之外, 不要使用右值引用.
    • 右值引用的語義比較複雜, 不恰當的使用會造成很難追查的bug.
  • 建議 include 的路徑、檔名與名稱空間保持一致
  • 使用空格縮排,不使用製表符。 以 4 個空格為單位縮排。避免超過 5 重的縮排。
  • 建議不要使用異常,除非已有專案/底層庫使用了異常, 這時候必須要catch所有異常。
  • 所有程式碼應該定義在namespace中, main函式除外。
  • 禁止內聯(inline)虛擬函式,inline函式應該在10行以內。
  • 函式靜止使用預設引數,模板可以使用預設引數。-- 預設引數是編譯期繫結的,不具有多型性。
  • 使用 auto 自動推導型別, 只能定義區域性變數(返回型別後置宣告除外).
  • 禁止使用 auto_ptr. 如果需要傳遞物件, 使用std::unique_ptr明確所有權傳遞. 如果要共享所有權, 使用std::shared_ptr明確所有權共享.
  • [RULE033] 避免對浮點數進行相等或不等比較。
    • 避免使用非布林型的變數或表示式作為分支語句條件。
    • 作相等比較時,建議把常量或右值變數放在 == 運算子的右邊。
  • 除非用於條件編譯、跟蹤除錯,或者能夠顯著減少程式碼量並確保可讀性的巨集(如 DISALLOW_COPY_AND_ASSIGN, CFATAL_LOG etc.),否則不應使用。
  • 鼓勵使用前向宣告,以減少檔案之間的依賴關係。
  • 儘可能避免使用全域性變數,如有必要應使用 singleton 模式代替。
    • 內部使用的全域性函式/變數,必須宣告為靜態函式、變數,不能在目標檔案中出現外部可見的符號。
  • 不應在標頭檔案定義類/結構體型別的全域性常量,以減少程式碼膨脹。
  • 可能用於跨模組間通訊或者涉及儲存的列舉值必須顯式指定值,避免版本不一致造成詭異的錯誤。
  • const 關鍵字用在型別名前面而非後面。
    • 不修改內部狀態的成員方法必須宣告為 const
    • 返回不可修改的指標或引用必須宣告為 const
    • 不被修改的引用/指標形參必須宣告為 const
    • 除非保證狀態不會被修改,不應使用 const_cast 來去掉 const 屬性
  • 避免定義超過 4 KB 的區域性變數陣列

風格/約定

  • 必須按以下順序引用標頭檔案,並進行分節:.cpp 對應的標頭檔案(如果有, // 優先位置), C(標準)庫,C++(標準)庫,其它庫,自己專案的.h檔案,每節內的include按照字母序。
  • 分行與空格:
    • 一條單獨的語句必須獨立成行。
    • 避免連續的空行。
    • 使用適當的空行來分組程式碼的邏輯。
    • 左大括號不獨立,右大括號獨立成行。並且左大括號所在行進行垂直對齊。
  • 名稱空間不縮排。
  • 建構函式初始化列表放在同一行或按至少八格縮排並排幾行, 如果需要換行, 把: 放在第一行。
  • 比較短的函式宣告,整個宣告佔一行;過長的函式宣告,令每一引數佔一行,並且垂直對齊, 換行後的引數至少保持 8 個空格縮排。
  • 比較短的函式呼叫語句,整個語句佔一行;過長的函式呼叫,控制折行確保每行不要超過 100 列,換行後至少額外縮排 8 個空格。
  • 空格的使用:
    • if/switch/while/for/catch 與後邊的圓括號之間加一個空格,圓括號內側與判斷表示式之間不加空格。
    • for語句圓括號內分號前不加空格,分號後加一個空格。
    • 函式呼叫中,函式名和圓括號之間不要加空格。
    • 類繼承與建構函式的初始化列表的冒號前後加一個空格。
    • 逗號表示式或引數列表中,逗號前不加空格,逗號後加一個空格。
    • 一元運算子前後不加空格。二元、三元表示式前後各加一個空格。
    • 成員訪問或作用域運算子前後不加空格。如:a.b, a->b, a.b, a->b, a::b。
    • 圓括號和方括號運算子前後和內部都不加空格。
  • .h 中不要定義複雜的函式, 複雜函式如果必須在標頭檔案中, 應該放在 .hpp 字尾的標頭檔案中。
  • 沒有使用到的函式引數,把引數名註釋起來, 不允許未命名引數出現。
    • :函式的引數順序,建議先安排輸入引數,再安排輸出引數。
    // 輸入引數物件型別使用const引用
    void foo(const std::string& input1, const MyClass& input2);

命名規範

  • 全域性可見的,卻又無法通過名稱空間約束的識別符號命名,必須以庫名作為字首,以避免衝突。
  • 命名應當儘可能有描述性,不使用非通用的縮寫(尤其是省一個字元的縮寫如creat,usr等),不使用有歧義的縮寫,不使用任意的無意義的字元.
  • 識別符號的作用域越大,命名就應該越清晰。
  • 可能使用多個單位名稱的變數(如表示時間的變數),應以單位名稱縮寫為字尾。
  • 檔名全部用小寫字母, 中間用_間隔; 比如: this_is_my_awesome_file.cpp.
  • 單元測試檔名使用_test.h(.cpp)命名.
  • 如果是要釋出供它人使用的 lib,推薦僅暴露一個以庫名同名,或者_.h的 api 標頭檔案,然後將相關標頭檔案 include 到這個 api 標頭檔案中。如:mylib.h,mylib_utils.h,mylib_api.h。
  • 使用下劃線分隔的全小寫命名法命名名稱空間。
  • 名稱空間名可以使用縮寫,同時應保證簡短、不易衝突但同時富有意義。
  • 函式命名使用下劃線分隔的全小寫命名法。
  • 函式通常使用動詞短語命名。
  • 自定義類型別使用首字母大寫的駝峰命名法命名,一般不使用字首。
  • 列舉型別成員,使用全大寫蛇形命名法(即全部字母大寫,單詞間用下劃線分隔)。
  • 儘可能不使用全域性變數,如果必須使用,必須以g為字首,而且必須足夠長以避免名字衝突。
  • 全域性變數使用下劃線分隔的全小寫命名法命名。
  • 區域性變數名使用下劃線分隔的全小寫命名法命名。
    • 假如區域性變數作用域很小,可以適當使用縮寫。
  • 全域性靜態變數 s_ 作為字首。類靜態成員使用 s 字首的下劃線分隔的全小寫命名法命名。
  • const 常量與列舉常量都使用下劃線分隔的全大寫命名法命名
  • 確定需要不同大小的變數,推薦使用<stdint.h>中定義的長度明確的整形型別,例如 int64_t, int32_t 等。
  • 多行註釋必須寫在被解釋內容的上方。單行註釋可以寫在被註釋語句的上文或右方。

  • 一行內只應宣告一個變數。
  • 區域性變數應儘量延遲到第一次使用處宣告。
  • 區域性變數應在宣告處賦初值,指標型別區域性變數必須在宣告處賦初值。
  • 本規範不適用於引入的公司外第三方程式碼, 修改時請遵守第三方程式碼自身的編碼風格。
  • 顯式或者通過巨集等隱式的定義派生自第三方程式碼中所申明的類,必須遵守對應第三方程式碼自身的編碼風格。

相關文章