C++代碼風格指南總結

來源:互聯網
上載者:User

標籤:邏輯   vector   eid   完全   資料類型   自己   靜態   設定   mes   

C++代碼風格指南代碼風格的重要性

今天我收到thougthwork筆試沒過的訊息, 心裡確實很難受, 然後師兄說我代碼寫得很糟糕
細想一下, 我寫代碼確實是隨心所欲, 並沒有遵循什麼規範; 所以現在下定決心痛改前非;

  • 首先第一步是代碼都自己一個字一個字的敲, 盡量減少Ctrl+CCtrl+V操作
  • 以後禁止使用tab鍵進行縮排,難道手敲四個空格會死麼?
  • 避免代碼冗長
  • Google開源項目C++代碼風格指南
標頭檔
  • 標頭檔包含順序
    1. 優先位置的包含檔案
    2. C系統檔案
    3. C++系統檔案
    4. 其他庫的.h檔案
    5. 本庫的.h檔案
範圍
  • 禁止使用 using 指示(using-directive)
  • 禁止使用內聯命名空間(inline namespace)
    • 因為內聯的命名空間會內部的標識符放到外層範圍
    • 內聯命名空間主要用來保持跨版本的 ABI 相容性
  • 在標頭檔中使用匿名空間導致違背 C++ 的唯一定義原則 (One Definition Rule (ODR)).
  • 不應該使用 using 指示引入整個命名空間的標識符號 ---- 會汙染命名空間
  • 不要在命名空間 std 內聲明任何東西, 包括標準庫的類前置聲明. 在 std 命名空間聲明實體是未定義的行為, 會導致如不可移植. 聲明標準庫下的實體, 需要包含對應的標頭檔.
  • 匿名命名空間和靜態空間(內部連結屬性)
    • 在 .cc 檔案中定義一個不需要被外部參考的變數時,可以將它們放在匿名命名空間或聲明為 static; 但是不要在 .h 檔案中這麼做
    • 所有置於匿名命名空間的聲明都具有內部連結性,函數和變數可以經由聲明為 static 擁有內部連結性,這意味著你在這個檔案中聲明的這些標識符都不能在另一個檔案中被訪問。即使兩個檔案聲明了完全一樣名字的標識符,它們所指向的實體實際上是完全不同的。
  • 靜態成員函數, 全域函數, 和非成員函數
    • 將一系列函數直接置於命名空間中,不要用類的靜態方法類比出命名空間的效果,類的靜態方法應當和類的執行個體或待用資料緊密相關.
  • 局部變數
    • 將函數變數儘可能置於最小範圍內, 並在變數聲明時進行初始化.
    • 提倡在儘可能小的範圍中聲明變數, 離第一次使用越近越好.
    • 這樣做的好處是閱讀代碼可以更容易定位變數的聲明位置, 瞭解變數的初始值和類型,特別是利用初始化的方式代替聲明再賦值的方式.
    • 警告: 如果變數是一個對象, 每次進入範圍都要調用其建構函式, 每次退出範圍都要調用其解構函式. 這會導致效率降低.
  • 靜態和全域變數
    • 禁止定義靜態儲存周期非POD變數(原生資料類型 (POD : Plain Old Data)),禁止使用含有副作用的函數初始化POD全域變數,因為多編譯單元中的靜態變數執行時的構造和析構順序是未明確的,這將導致代碼的不可移植.
    • 靜態變數的建構函式和解構函式在C++中只有部分明確確定, 甚至隨著構建變化而變化, 導致難以發現的bug.
    • 盡量不要使用函數的傳回值來初始化一個變數
    • 同一個編譯單元內是明確的,靜態初始化優先於動態初始化,初始化順序按照聲明順序進行,銷毀則逆序。
    • 不同的編譯單元之間初始化和銷毀順序屬於未明確行為 (unspecified behaviour)。
    • 全域和靜態變數在程式中斷時會被析構, --- 析構順序和建構函式的調用順序相反。
    • quick_exit() 來代替 exit() 並中斷程式。quick_exit 不會執行任何析構,也不會執行 atexit() 所綁定的任何 handlers.
    • 只允許 POD(原生資料類型) 類型的靜態變數
    • static 對象, 可以考慮在 main() 函數或 pthread_once() 內初始化一個指標且永不回收, 只能使用raw指標.
    • 別用智能指標,畢竟後者的解構函式涉及不定順序問題
    • 匿名命名空間說白了就是檔案範圍,就像 C static 聲明的範圍一樣,後者已經被 C++ 標準提倡棄用
    • 局部變數在聲明的同時進行顯式值初始化,比起隱式初始化再賦值的兩步過程要高效,同時也貫徹了電腦體繫結構重要的概念「局部性(locality)」
  • 不要在建構函式中調用虛函數, 也不要在無法報出錯誤時進行可能失敗的初始化.
  • 建構函式的地址是無法被取得的, 因此, 舉例來說, 由建構函式完成的工作是無法以簡單的方式交給其他線程的.
  • 不要定義隱式類型轉換. 對於轉換運算子和單參數建構函式, 請使用 explicit 關鍵字.
  • 在類型定義中, 類型轉換運算子和單參數建構函式都應當用 explicit 進行標記. 一個例外是, 拷貝和移動建構函式不應當被標記為 explicit, 因為它們並不執行類型轉換. 對於設計目的就是用於對其他類型進行透明封裝的類來說, 隱式類型轉換有時是必要且合適的. 這時應當聯絡項目組長並說明特殊情況.
  • 僅當只有資料成員時使用 struct, 其它一概使用 class.
  • 為了和 STL 保持一致, 對於仿函數等特性可以不用 class 而是使用 struct.
  1. 不在建構函式中做太多邏輯相關的初始化;
  2. 編譯器提供的預設建構函式不會對變數進行初始化, 如果定義了其他建構函式, 編譯器不再提供, 需要編碼者自行提供預設建構函式;
  3. 為避免隱式轉換, 需將單參數建構函式聲明為 explicit;
  4. 為避免拷貝建構函式, 賦值操作的濫用和編譯器自動產生, 可將其聲明為 private 且無需實現;
  5. 僅在作為資料集合時使用 struct;
  6. 組合 > 實現繼承 > 介面繼承 > 私人繼承, 子類重載的虛函數也要聲明 virtual 關鍵字, 雖然編譯器允許不這樣做;
  7. 避免使用多重繼承, 使用時, 除一個基類含有實現外, 其他基類均為純介面;
  8. 介面類類名以 Interface 為尾碼, 除提供帶實現的虛解構函式, 靜態成員函數外, 其他均為純虛函數, 不定義非待用資料成員, 不提供建構函式, 提供的話, 聲明為 protected;
  9. 為降低複雜性, 盡量不重載操作符, 模板, 標準類中使用時提供文檔說明;
  10. 存取函數一般內聯在標頭檔中;
  11. 聲明次序: public -> protected -> private;
  12. 函數體盡量短小, 緊湊, 功能單一;
函數
  • 在排列參數順序時, 將所有的輸入參數置於輸出參數之前. 特別要注意, 在加入新參數時不要因為它們是新參數就置於參數列表最後, 而是仍然要按照前述的規則, 即將新的輸入參數也置於輸出參數之前.
  • 傾向於編寫簡短, 凝練的函數.
  • 可以思索一下能不能在不影響程式結構的前提下對其進行分割.
  • 所有按引用傳遞的參數必須加上 const.
  • 定義引用參數可以防止出現 (*pval)++ 這樣醜陋的代碼. 引用參數對於拷貝建構函式這樣的應用也是必需的. 同時也更明確地不接受null 指標.
  • 引用在文法上是值變數卻擁有指標的語義.
  • 輸入參數是值參或 const 引用, 輸出參數為指標. 輸入參數可以是 const 指標, 但決不能是非 const 的引用參數, 除非特殊要求, 比如 swap().
  • 只允許在非虛函數中使用預設參數, 且必須保證預設參數的值始終一致.
  • 對於虛函數, 不允許使用預設參數, 因為在虛函數中預設參數不一定能正常工作.
  • 只有在常規寫法 (傳回型別前置) 不便於書寫或不便於閱讀時使用傳回型別後置文法. --- 後置傳回型別是顯式地指定 Lambda 運算式 的傳回值的唯一方式.
來自Google的奇技
  • Google用了很多自己實現的技巧/工具C++代碼更加健壯
  • 所有權與智能指標: 動態分配出的對象最好有單一且固定的所有主, 並通過智能指標傳遞所有權.
  • 智能指標是重載了*->運算子以表現得像指標一樣的類
    • unique_ptr將所有權移動給新所有主
    • shared_ptr表示動態指派至的所有權, 但可以被共用, 也可以被複製
  • 如果沒有很好的理由就不要使用共用版所有權, 是為了避免開銷昂貴的拷貝操作.
  • 不要使用auto_ptr, 使用shared_ptr代替它.
  • 使用cpplint.py檢查代碼風格, cpplint.py是一個用來分析源檔案, 能檢查出多種風格錯誤的工具.
  • scoped_ptr 和 auto_ptr 已淘汰. 現在是 shared_ptr 和 uniqued_ptr 的天下了.
  • AUR有對cpplint打包.
其他C++特性
  • 引用參數: 所有按引用傳遞的參數必須加上const
    • 引用在文法上是值變數卻擁有指標的語義.
    • 輸入參數是值參或 const 引用, 輸出參數為指標. 輸入參數可以是 const 指標, 但決不能是非 const 的引用參數,除非用於交換.
    • 有時候,在輸入形參中用 const T* 指標比 const T& 更明智.
  • 右值的引用: 只在定義移動建構函式與移動賦值操作時使用右值引用. 不要使用 std::forward.
    • 右值引用是一種只能綁定到臨時對象的引用的一種, 其文法與傳統的引用文法相似.
    • 用於定義移動建構函式 (使用類的右值引用進行構造的函數) 使得移動一個值而非拷貝之成為可能.
    • 要高效率地使用某些標準庫類型, 例如 std::unique_ptr, std::move 是必需的.
  • 函數重載: 若要用好函數重載,最好能讓讀者一看調用點(call site)就胸有成竹,不用花心思猜測調用的重載函數到底是哪一種。該規則適用於建構函式.
    • 模板化代碼需要重載, 同時為使用者帶來便利.
  • 預設參數: 我們不允許使用預設函數參數,少數極端情況除外。儘可能改用函數重載.
    • 預設參數會干擾函數簽名(function signature), 往往對不上所實際要調用的函數簽名
    • 其一,位於 .cc 檔案裡的靜態函數或匿名空間函數,畢竟都只能在局部檔案裡調用該函數了。
    • 其二,可以在建構函式裡用預設參數,畢竟不可能取得它們的地址。
    • 其三,可以用來類比變長數組。
  • 變長數組和alloca()
    • 我們不允許使用變長數組和 alloca().
    • 變長數組具有渾然天成的文法. 變長數組和 alloca() 也都很高效; 但是不是標準C++文法的一部分.
    • 改用更安全的分配器(allocator),就像 std::vector 或 std::unique_ptr<T[]>
  • 友元(friend)
    • 我們允許合理的使用友元類及友元函數.
    • 通常友元應該定義在同一檔案內, 避免代碼讀者跑到其它檔案尋找使用該私人成員的類.
    • 將一個單元測試類聲明成待測類的友元會很方便.
    • 友元擴大了 (但沒有打破) 類的封裝邊界. 某些情況下, 相對於將類成員聲明為 public, 使用友元是更好的選擇, 尤其是如果你只允許另一個類訪問該類的私人成員時. 當然, 大多數類都只應該通過其提供的公有成員進行互操作.
  • 異常
    • 我們不使用 C++ 異常.
    • 異常允許應用高層決定如何處理在底層嵌套函數中「不可能發生」的失敗(failures),不用管那些含糊且容易出錯的錯誤碼.
    • 異常是處理建構函式失敗的唯一途徑.
    • 異常會徹底擾亂程式的執行流程並難以判斷,函數也許會在您意料不到的地方返回.
    • 對於異常處理, 顯然不是短短几句話能夠說清楚的, 以建構函式為例, 很多 C++ 書籍上都提到當構造失敗時只有異常可以處理, Google 禁止使用異常這一點, 僅僅是為了自身的方便, 說大了, 無非是基於軟體管理成本上, 實際使用中還是自己決定
  • 運行時類型識別(run time type information RTTI)
    • RTTI 允許程式員在運行時識別 C++ 類對象的類型. 它通過使用 typeid 或者 dynamic_cast 完成.
    • 在單元測試中可以使用 RTTI, 但是在其他代碼中請盡量避免. 尤其是在新代碼中, 使用 RTTI 前務必三思. 如果你的代碼需要根據不同的物件類型執行不同的行為的話, 請考慮用以下的兩種替代方案之一查詢類型.
    • 虛函數可以根據子類類型的不同而執行不同代碼.
  • 類型轉型
    • 使用 C++ 的類型轉換, 如 static_cast<>(). 不要使用 int y = (int)x 或 int y = int(x) 等轉換方式
    • C++ 採用了有別於 C 的類型轉換機制, 對轉換操作進行歸類.
    • 用 static_cast 替代 C 風格的值轉換, 或某個類指標需要明確的向上轉換為父類指標時.
    • 用 const_cast 去掉 const 限定符.
    • 用 reinterpret_cast 指標類型和整型或其它指標之間進行不安全的相互轉換. 僅在你對所做一切瞭然於心時使用.
    • 用 dynatic_cast 將衍生類別指標轉換為基類類型, 或將基類指標轉換為衍生類別指標.
    • 只在記錄日誌時使用流.
    • 流用來替代 printf() 和 scanf().
    • 有了流, 在列印時不需要關心對象的類型.
    • 流的構造和解構函式會自動開啟和關閉對應的檔案.
    • 使用流還有很多利弊, 但代碼一致性勝過一切. 不要在代碼中使用流.
    • 回想一下唯一性原則 (Only One Way): 我們希望在任何時候都只使用一種確定的 I/O 類型, 使代碼在所有 I/O 處都保持一致.
    • 簡單性原則告誡我們必須從中選擇其一, 最後大多數決定採用 printf + read/write.
  • 前置自增或自減
    • 對於迭代器和其他模板對象使用首碼形式 (++i) 的自增, 自減運算子.
    • 不考慮傳回值的話, 前置自增 (++i) 通常要比後置自增 (i++) 效率更高. 因為後置自增 (或自減) 需要對錶達式的值 i 進行一次拷貝.
    • 對簡單數值 (非對象), 兩種都無所謂. 對迭代器和模板類型, 使用前置自增 (自減).
  • const 用法
    • 我們強烈建議你在任何可能的情況下都要使用 const. 此外有時改用 C++11 推出的 constexpr 更好.
    • 在聲明的變數或參數前加上關鍵字 const 用於指明變數值不可被篡改 (如 const int foo ). 為類中的函數加上 const 限定符表明該函數不會修改類成員變數的狀態
    • 大家更容易理解如何使用變數. 編譯器可以更好地進行類型檢測, 相應地, 也能產生更好的代碼.
    • 如果函數不會修改傳你入的引用或指標型別參數, 該參數應聲明為 const.
    • 儘可能將函式宣告為 const. 訪問函數應該總是 const. 其他不會修改任何資料成員, 未調用非 const 函數, 不會返回資料成員非 const 指標或引用的函數也應該聲明成 const.
    • 如果資料成員在物件建構之後不再發生變化, 可將其定義為 const.
    • 關鍵字 mutable 可以使用, 但是在多線程中是不安全的, 使用時首先要考慮安全執行緒.
    • 保持代碼的一致性: 也就是不要在一些地方把 const 寫在類型前面, 在其他地方又寫在後面, 確定一種寫法, 然後保持一致.
  • constexpr 用法
    • 在 C++11 裡,用 constexpr 來定義真正的常量,或實現常量初始化
    • 變數可以被聲明成 constexpr 以表示它是真正意義上的常量,即在編譯時間和運行時都不變。函數或建構函式也可以被聲明成 constexpr, 以用來定義 constexpr 變數
    • 靠 constexpr 特性,方才實現了 C++ 在介面上打造真正常量機制的可能。好好用 constexpr 來定義真?常量以及支援常量的函數。避免複雜的函數定義,以使其能夠與constexpr一起使用。 千萬別癡心妄想地想靠 constexpr 來強制代碼「內聯
    • constexpr關鍵字詳解
    • constexpr編譯時間常量
  • 整數
    • C++ 內建整型中, 僅使用 int. 如果程式中需要不同大小的變數, 可以使用 <stdint.h> 中長度精確的整型, 如 int16_t.如果您的變數可能不小於 2^31 (2GiB), 就用 64 位元變數比如 int64_t. 此外要留意,哪怕您的值並不會超出 int 所能夠表示的範圍,在計算過程中也可能會溢出。所以拿不準時,乾脆用更大的類型
    • C++ 沒有指定整型的大小. 通常人們假定 short 是 16 位, int 是 32 位, long 是 32 位, long long 是 64 位元.
    • C++ 中整型大小因編譯器和體繫結構的不同而不同.
    • 應該使用斷言來保護資料.
    • 使用斷言來指出變數為非負數, 而不是使用無符號型
  • 64位下的可移植性
    • 代碼應該對 64 位元和 32 位系統友好. 處理列印, 比較, 結構體對齊時應切記
    • 持久化 - 將資料按位元組流順序儲存在磁碟檔案或資料庫中.
    • gcc 中可使用 __attribute__((packed))使結構體對齊
  • 預先處理宏
    • 使用宏時要非常謹慎, 盡量以內嵌函式, 枚舉和常量代替之.
    • 宏意味著你和編譯器看到的代碼是不同的. 這可能會導致異常行為, 尤其因為宏具有全域範圍.
    • 下面給出的用法模式可以避免使用宏帶來的問題; 如果你要宏, 儘可能遵守:
      • 不要在 .h 檔案中定義宏.
      • 在馬上要使用時才進行 #define, 使用後要立即 #undef.
      • 不要只是對已經存在的宏使用#undef,選擇一個不會衝突的名稱;
      • 不要試圖使用展開後會導致 C++ 構造不穩定的宏, 不然也至少要附上文檔說明其行為.
      • 不要用 ## 處理函數,類和變數的名字
  • 0 , NULL 和 nullptr
    • 整數用 0, 實數用 0.0, 指標用 nullptr 或 NULL, 字元 (串) 用 ‘\0‘.
    • 對於指標 (地址值), 到底是用 0, NULL 還是 nullptr. C++11 項目用 nullptr; C++03 項目則用 NULL, 畢竟它看起來像指標。實際上,一些 C++ 編譯器對 NULL 的定義比較特殊,可以輸出有用的警告,特別是 sizeof(NULL) 就和 sizeof(0) 不一樣。
    • 字元 (串) 用 ‘\0‘, 不僅類型正確而且可讀性好.
  • sizeof
    • 儘可能用 sizeof(varname) 代替 sizeof(type).
  • auto
    • 用 auto 繞過煩瑣的類型名,只要可讀性好就繼續用,別用在局部變數之外的地方
    • C++11 中,若變數被聲明成 auto, 那它的類型就會被自動匹配成初始設定式的類型
    • 代碼要避免無所謂的重複
    • auto 只能用在局部變數裡用。別用在檔案範圍變數,命名空間範圍變數和類資料成員裡。永遠別列表初始化 auto 變數
    • auto 還可以和 C++11 特性「尾置傳回型別(trailing return type)」一起用,不過後者只能用在 lambda 運算式裡
  • 初始化列表
    • C++11 中,該特性得到進一步的推廣,任何物件類型都可以被列表初始化
    • 使用者自訂類型也可以定義接收 std::initializer_list
    • 列表初始化也適用於常規資料類型的構造,哪怕沒有接收 std::initializer_list
  • Lambda運算式
    • 適當使用 lambda 運算式。別用預設 lambda 捕獲,所有捕獲都要顯式寫出來
    • Lambda 運算式是建立匿名函數對象的一種簡易途徑,常用於把函數當參數傳
    • Lambdas, std::functions 和 std::bind 可以搭配成通用回調機制(general purpose callback mechanism);寫接收有界函數為參數的函數也很容易了
    • 按 format 小用 lambda 運算式怡情。
    • 禁用預設捕獲,捕獲都要顯式寫出來。打比方,比起 = {return x + n;}, 您該寫成 n {return x + n;} 才對,這樣讀者也好一眼看出 n 是被捕獲的值。
    • 匿名函數始終要簡短,如果函數體超過了五行,那麼還不如起名(acgtyrant 註:即把 lambda 運算式賦值給對象),或改用函數。
    • 如果可讀性更好,就顯式寫出 lambd 的尾置傳回型別,就像auto.
  • 模板編程
    • 不要使用複雜的模板編程
    • 模板編程指的是利用c++ 模板執行個體化機制是圖靈完備性, 可以被用來實現編譯時間刻的類型判斷的一系列編程技巧
    • 模板編程的優缺點
  • Boost庫
    • 只使用 Boost 中被認可的庫.
  • C++11
    • 適當用 C++11(前身是 C++0x)的庫和語言擴充,在貴項目用 C++11 特性前三思可移植性
命名規約
  • 最重要的一致性規則是命名管理.
  • 類型, 變數, 函數, 常量, 宏, 等等, 甚至. 我們大腦中的模式比對引擎非常依賴這些命名規則.
  • 命名規約的一致性更重要, 所以無論你認為它們是否重要, 規則總歸是規則.
  • 通用命名規則
    • 函數命名, 變數命名, 檔案命名要有描述性; 少用縮寫.
    • 儘可能使用描述性的命名, 別心疼空間, 畢竟相比之下讓代碼易於新讀者理解更重要. 不要用只有項目開發人員能理解的縮寫, 也不要通過砍掉幾個字母來縮寫單詞.
  • 檔案命名
    • 檔案名稱要全部小寫, 可以包含底線 () 或連字號 (-), 依照項目的約定. 如果沒有約定, 那麼 “” 更好.
  • 類型命名
    • 類型名稱的每個單詞首字母均大寫, 不包含底線: MyExcitingClass, MyExcitingEnum.
    • 所有類型命名 —— 類, 結構體, 類型定義 (typedef), 枚舉, 類型模板參數 —— 均使用相同約定, 即以大寫字母開始, 每個單詞首字母均大寫, 不包含底線.
  • 變數命名
    • 變數 (包括函數參數) 和資料成員名一律小寫, 單詞之間用底線串連.
    • 類的成員變數以底線結尾, 但結構體的就不用, 如: a_local_variable, a_struct_data_member, a_class_data_member_.
    • 普通變數一律小寫
    • 不管是靜態還是非靜態, 結構體資料成員都可以和普通變數一樣, 不用像類那樣接底線
  • 常量命名
    • 聲明為 constexpr 或 const 的變數, 或在程式運行期間其值始終保持不變的, 命名時以 “k” 開頭, 大小寫混合.
  • 函數命名
    • 常規函數使用大小寫混合, 取值和設值函數則要求與變數名匹配
    • 一般來說, 函數名的每個單字首大寫 (即 “駝峰變數名” 或 “帕斯卡變數名”), 沒有底線. 對於首字母縮寫的單詞, 更傾向於將它們視作一個單詞進行首字母大寫 (例如, 寫作 StartRpc() 而非 StartRPC()).
  • 命名空間命名
    • 命名空間以小寫字母命名.
    • 最進階命名空間的名字取決於項目名稱.
    • 要注意避免嵌套命名空間的名字之間和常見的頂級命名空間的名字之間發生衝突.
    • 注意 不使用縮寫作為名稱 的規則同樣適用於命名空間. 命名空間中的代碼極少需要涉及命名空間的名稱, 因此沒有必要在命名空間中使用縮寫.
  • 枚舉命名
    • 枚舉的命名應當和 常量 或 宏 一致: kEnumName 或是 ENUM_NAME.
    • 單獨的枚舉值應該優先採用 常量 的命名方式. 但 宏 方式的命名也可以接受.
  • 宏命名
    • 宏命名像這樣命名: MY_MACRO_THAT_SCARES_SMALL_CHILDREN.
    • 通常 不應該 使用宏. 如果不得不用, 其命名像枚舉命名一樣全部大寫, 使用底線
  • 感覺 Google 的命名規範很高明, 比如寫了簡單的類 QueryResult, 接著又可以直接定義一個變數 query_result, 區分度很好; 再次, 類內變數以底線結尾, 那麼就可以直接傳入同名的形參, 比如 TextQuery::TextQuery(std::string word) : word_(word) {} , 其中 word_ 自然是類內私人成員.
注釋
  • 注釋雖然寫起來很痛苦, 但對保證代碼可讀性至關重要.
  • 注釋固然很重要, 但最好的代碼應當本身就是文檔. 有意義的類型名和變數名, 要遠勝過要用注釋解釋的含糊不清的名字.
  • 注釋風格
    • 使用///* ···*/, 統一風格就好.
  • 檔案注釋:
    • 在每個檔案開頭加入著作權公告, 檔案注釋描述了該檔案的內容. 如果一個檔案只聲明, 或實現, 或測試了一個對象, 並且這個對象已經在它的聲明處進行了詳細的注釋, 那麼就沒必要再加上檔案注釋. 除此之外的其他檔案都需要檔案注釋.
    • 不要在 .h 和 .cc 之間複製注釋, 這樣的注釋偏離了注釋的實際意義.
  • 類注釋:
    • 每個類的定義都要附帶一份注釋, 描述類的功能和用法, 除非它的功能相當明顯.
    • 描述類用法的注釋應當和介面定義放在一起, 描述類的操作和實現的注釋應當和實現放在一起.
  • 函數注釋:
    • 函式宣告處的注釋描述函數功能; 定義處的注釋描述函數實現.
    • 基本上每個函式宣告處前都應當加上注釋, 描述函數的功能和用途. 只有在函數的功能簡單而明顯時才能省略這些注釋(例如, 簡單的取值和設值函數).
  • 讓代碼自文檔化.
  • 注意標點, 拼字和文法; 寫的好的注釋比差的要易讀的多.
  • TODO注釋風格
  • 關於注釋風格, 很多 C++ 的 coders 更喜歡行注釋, C coders 或許對塊注釋依然情有獨鐘, 或者在檔案頭大段大段的注釋時使用塊注釋;
  • 檔案注釋可以炫耀你的成就, 也是為了捅了簍子別人可以找你;
  • 注釋要言簡意賅, 不要拖遝冗餘, 複雜的東西簡單化和簡單的東西複雜化都是要被鄙視的;
  • 對於 Chinese coders 來說, 用英文注釋還是用中文注釋, it is a problem, 但不管怎樣, 注釋是為了讓別人看懂, 難道是為了炫耀程式設計語言之外的你的母語或外語水平嗎;
  • 注釋不要太亂, 適當的縮排才會讓人樂意看. 但也沒有必要規定注釋從第幾列開始 (我自己寫代碼的時候總喜歡這樣), UNIX/LINUX 下還可以約定是使用 tab 還是 space, 個人傾向於 space;
  • TODO 很不錯, 有時候, 注釋確實是為了標記一些未完成的或完成的不盡如人意的地方, 這樣一搜尋, 就知道還有哪些活要幹, 日誌都省了.
格式
  • 每個人都可能有自己的代碼風格和格式, 但如果一個項目中的所有人都遵循同一風格的話, 這個項目就能更順利地進行. 每個人未必能同意下述的每一處格式規則, 而且其中的不少規則需要一定時間的適應, 但整個項目服從統一的編程風格是很重要的, 只有這樣才能讓所有人輕鬆地閱讀和理解代碼.
  • 行長度:
    • 每行最多80個字元
  • 盡量不使用非 ASCII 字元, 使用時必須使用 UTF-8 編碼.
  • 我們使用空格縮排. 不要在代碼中使用定位字元. 你應該設定編輯器將定位字元轉為空白格.
  • 使用好的參數名.
  • 只有在參數未被使用或者其用途非常明顯時, 才能省略參數名.
  • 如果傳回型別和函數名在一行放不下, 分行.
  • 如果傳回型別與函式宣告或定義分行了, 不要縮排.
  • 左圓括弧總是和函數名在同一行.
  • 函數名和左圓括弧間永遠沒有空格.
  • 圓括弧與參數間沒有空格.
  • 左大括弧總在最後一個參數同一行的末尾處, 不另起新行.
  • 右大括弧總是單獨位於函數最後一行, 或者與左大括弧同一行.
  • 右圓括弧和左大括弧間總是有一個空格.
  • 所有形參應儘可能對齊.
  • 預設縮排為 2 個空格.
  • 換行後的參數保持 4 個空格的縮排.
  • 水平留白的使用根據在代碼中的位置決定. 永遠不要在行尾添加沒意義的留白.

C++代碼風格指南總結

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.