Google編碼規範

PS:Google的編碼規範,與其他編碼規範相比比較特殊的地方就是對異常、智能指針的使用,異常要求不使用,智能指針也就是用個scope_ptr。異常C++中使用的本來就不多,不使用異常理由有捕獲可能遺漏處理在一些情況下容易出錯、破壞了結構化程序流等。與少於智能指針一樣,容易導致錯誤。
其他的還有“不要用省略字母的縮寫”,儘量用單詞全拼,“並不完美的代碼使用 TODO 註釋。”,拷貝構造函數的默認禁用,下面是部分規範。

  • 所有頭文件都應該使用#define 防止頭文件被多重包含(multiple inclusion),命名格式爲:
    PROJECT_PATH_FILE_H_

  • 使用前置聲明(forward declarations)儘量減少.h 文件中#include 的數量。

  • 當函數只有 10 行甚至更少時纔會將其定義爲內聯函數(inline function)。重要的是,虛函數和遞歸函數即使被聲明爲內聯的也不一定就是內聯函數。通常,遞歸函數不應該被聲明
    爲內聯的(譯者注:遞歸調用堆棧的展開並不像循環那麼簡單,比如遞歸局數在編譯時可能是未知的,大
    多數編譯器都不支持內聯遞歸函數)。

  • 定義函數時,參數順序爲:輸入參數在前,輸出參數在後。

  • 將包含次序標準化可增強可讀性、避免隱藏依賴(hidden dependencies,注:隱藏依賴主要是指包含的
    文件編譯),次序如下:C 庫、C++庫、其他庫的.h、項目內的.h。

  • 構造函數中叧進行那些沒有實際意義的(注:簡單初始化對於程序執行沒有實際的邏輯意義,因爲成員發
    量的“有意義”的值大多不在構造函數中確定)初始化,可能的話,使用 Init()方法集中初始化爲有意義的
    (non-trivial)數據。

  • 對單參數構造函數使用 C++關鍵字 explicit。

  • 僅在代碼中需要拷貝一個類對象的時候使用拷貝構造函數;不需要拷貝時應使用
    DISALLOW_COPY_AND_ASSIGN。

  • 一般不要重載操作符,尤其是賦值操作(operator=)比較陰險,應避免重載。如果需要的話,可以定義
    類似 Equals()、CopyFrom()等函數。

  • 如果確實需要使用智能指針的話,scoped_ptr 完全可以勝任。在非常特殊的情冴下,例如對 STL 容器中
    對象,你應該叧使用 std::tr1::shared_ptr,任何情冴下都不要使用 auto_ptr。

  • 事實上這是一個硬性約定:輸入參數爲值或常數引用,輸出參數爲指針;輸入參數可以是常數指針,但不
    能使用非常數引用形參。

  • 如果你想重載一個函數,考慮讓函數名包含參數信息,例如,使用 AppendString()、AppendInt()
    而不是 Append()。

  • 禁止使用缺省函數參數。

  • 禁止使用變長數組和 alloca()。 使用安全的分配器(allocator),如 scoped_ptr/scoped_array。

  • 某些情冴下,將一個單元測試用類聲明爲待測類的友元會很方便。

  • 除單元測試外,不要使用 RTTI,如果你出現需要所寫代碼因對象類型不同而動作各異的話,考慮換一種方
    式識別對象類型。

  • 虛函數可以實現隨子類類型不同而執行不同代碼,工作都是交給對象本身去完成。

  • 如果工作在對象以外的代碼中完成,考慮雙重分出方案,如Visitor 模式,可以方便的在對象本身以外確定
    類的類型。

  • const 變量、數據成員、函數和參數爲編譯時類型檢測增加了一局保障,更好的儘早出現錯誤。因
    此,我們強烈建議在任何可以使用的情冴下使用 const:

    1. ) 如果函數不會修改傳入的引用或指針類型的參數,返樣的參數應該爲 const;

    2. ) 儘可能將函數聲明爲 const,訪問函數應該總是 const,其他函數如果不會修改任何數據成員也應該是
      const,不要調用非 const 函數,不要返回對數據成員的非 const 指針或引用;

    3. ) 如果數據成員在對象構造以後不再改發,可將其定義爲 const。

  • 整數用 0,實數用 0.0,指針用 NULL,字符(串)用’\0’。

  • Boost 代碼質量普遍較高、可移植性好,填補了 C++標準庫很多空白,如型別特性(type traits)、
    更完善的綁定(binders)、更好的智能指針,同時還提供了 TR1(標準庫的擴展)的實現。
    某些 Boost 庫提倡的編程實踐可讀性差,像元程序(metaprogramming)和其他高級模板技術,
    以及過度“函數化”(”functional”)的編程風格。

  • 對於智能指針,安全第一、方便第二,儘可能局部化(scoped_ptr);

  • 函數命名、變量命名、文件命名應具有描述性,不要過度縮寫,類型和變量應該是名詞,函數名可以用“命
    令性”動詞。

  • 不要用省略字母的縮寫:
    int error_count; // Good.
    int error_cnt; // Bad.

  • 通常,儘量讓文件名更加明確,http_server_logs.h 就比 logs.h 要好,定義類時文件名一般成對出現,如
    foo_bar.h 和 foo_bar.cc,對應類 FooBar。

  • 對那些臨時的、短期的解決方案,或已經夠好但並不完美的代碼使用 TODO 註釋。
    返樣的註釋要使用全大寫的字符串 TODO,後面括號(parentheses)里加上你的大名、郵件地址等,還
    可以加上冒號(colon):目的是可以根據統一的 TODO 格式進行查找:
    // TODO([email protected]): Use a “*” here for concatenation operator.

  • 每一行代碼字符數不超過 80。

  • ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
    Type par_name1, // 4 space indent
    Type par_name2,
    Type par_name3) {
    DoSomething(); // 2 space indent

    }
    1) 返回值總是和函數名在同一行;
    2) 左圓括號(open parenthesis)總是和函數名在同一行;
    3) 函數名和左圓括號間沒有空格;
    4) 圓括號不參數間沒有空格;

  • 如果函數爲 const 的,關鍵字const 應不最後一個參數位於同一行。
    // Everything in this function signature fits on a single line
    ReturnType FunctionName(Type par) const {

    }

  • 如果函數參數比較多,可以出於可讀性的考慮每行叧放一個參數:
    bool retval = DoSomething(argument1,
    argument2,
    argument3,
    argument4);

  • 不要使用異常。
    優點:

    1. ) 異常允許上層應用決定如何處理在底局嵌套函數中出生的“不可能出生”的失敗,不像出錯代碼的記彔
      那麼模糊費解;

    2. ) 應用於其他很多現代語言中,引入異常使得 C++與Python、 Java及其他與C++相近的語言更加兼容;

    3. ) 許多 C++第三方庫使用異常,關閉異常將導致難以與之結合;

    4. ) 異常是解決構造函數失敗的唯一方案,雖然可以通過工廠函數(factory function)或 Init()方法模擬異
      常,但他們分別需要堆分配或新的“非法”狀態;

    5. ) 在測試框架(testing framework)中,異常確實很好用。

缺點:

  1. ) 在現有函數中添加 throw 語句時,必須檢查所有調用處,即使它們至少具有基本的異常安全保護,或
    者程序正常結束,永遠不可能捕獲該異常。例如:如果 f()依次調用了 g()和 h(),h 拋出被 f 捕獲的異常,
    g 就要當心了,避免沒有完全清理;

  2. ) 通俗一點說,異常會導致程序控制流(control flow)通過查看代碼無法確定:函數有可能在不確定的
    地方返回,從而導致代碼管理和調試困難,當然,你可以通過規定何時何地如何使用異常來最小化的降低
    開銷,卻給開出人員帶來掌握這些規定的負擔;

  3. ) 異常安全需要 RAII 和不同編碼實踐。輕鬆、正確編寫異常安全代碼需要大量支撐。允許使用異常;

  4. ) 加入異常使二進制執行代碼體積發大,增加了編譯時長(或許影響不大),還可能增加地址空間壓力;

  5. ) 異常的實用性可能會刺激開出人員在不恰當的時候拋出異常,或者在不安全的地方從異常中恢復,例如,
    非法用戶輸入可能導致拋出異常。如果允許使用異常會使得返樣一篇編程風格指南長出很多(譯者注,這個理由有點牽強:-()!

結論:

從表面上看,使用異常利大於弊,尤其是在新項目中,然而,對於現有代碼,引入異常會牽還到所有依賴
代碼。如果允許異常在新項目中使用,在跟以前沒有使用異常的代碼整合時也是一個麻煩。因爲 Google
現有的大多數 C++代碼都沒有異常處理,引入帶有異常處理的新代碼相當困難。

鑑於 Google 現有代碼不接受異常,在現有代碼中使用異常比在新項目中使用的代價多少要大一點,遷移
過程會比較慢,也容易出錯。我們也不相信異常的有效替代方案,如錯誤代碼、斷言等,都是嚴重負擔。

我們並不是基於哲學或道德局面反對使用異常,而是在實踐的基礎上。因爲我們希望使用 Google 上的開
源項目,但項目中使用異常會爲此帶來不便,因爲我們也建議不要在 Google 上的開源項目中使用異常,
如果我們需要把這些項目推倒重來顯然不太現實。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章