📜

Google C++ Style Guide要約(一部)

2021/01/12に公開

「Google C++ スタイルガイド 日本語全訳」のメモ
https://ttsuki.github.io/styleguide/cppguide.ja.html

禁止事項

  • マクロをヘッダで定義する×
  • using の使用を極力禁止
    using ::testing::ほげほげ;  // NG
    
  • std::auto_ptr ではなく std::unique_ptr を使うこと

ネーミングルール(命名規則)

  • 全般
    • 名前の分かり易さ > 短い名前
    • 省略形は広く一般に知られたもののみにする(具体的にはWikipediaレベル)
  • 一覧表
要素 つづり方 記号
変数名 小文字 _ table_name, tablename
クラスのメンバ名 小文字、最後に _ をつける _ table_name_
定数名(静的変数、グローバル変数)/列挙型のメンバ 最初に k をつける、区切りごとに大文字 _ kAndroid8_0_0
定数名(ローカル変数など上記以外) 小文字 _ table_name, tablename
定義値 すべて大文字 _ PI_ROUNDED
関数名/クラス名/列挙型の名前 大文字始まり、区切りごとに大文字 なし AddTableEntry
ファイル名 すべて小文字 _ または - my_useful_class.cpp
型名 大文字始まり、区切りごとに大文字 なし UrlTable

スペース位置と改行

  • スペースが1つ必要
    • 閉じ丸カッコと開き波カッコの間:) {
    • コロンの前後:for (auto : counts)
      • case文は除く
  • スペースは不要
    • 関数名と開き丸カッコの間:func(
    • 開き丸カッコと変数の間:(int a
    • テンプレートの<>の中:<int>
    • ピリオド、アロー演算子の周り:a.b, a->c
    • ポインタ演算子と変数名との間:&x, *y
      • 変数、引数をポインタとして宣言するときはどちらにつけていい:char *c, char* c
    • セミコロンの前:... = 0;
    • 波かっこでの初期化リストの内側:{1, 2}
  • 改行しない(改行マークを\nで示す)
    • 開き丸カッコは常に関数名と同じ行に書く:func(\n
    • 開き波カッコは常に関数宣言の最後に書く:...) {\n
    • 閉じ波カッコは、それ自身で最後とするか、開き波カッコと同じ行に書くかのいずれか:}\n or {...}
    • ファイルの行末(マージ時の余計な手間をなくす)
int func<int>(int a, ...) {

変数

ローカル変数

関数内で宣言するとき

  • スコープはできるだけ狭くする
    =使う直前に宣言する(Cとは異なるので注意)
    • ループ内でオブジェクトを宣言する場合は、ループの直前でもいい
      理由: ループのたびにコンストラクタが呼び出され、性能が落ちるから
  • 宣言と同時に初期化する(1行で)
    • ※for文などの直前で宣言した場合は初期化しなくてもいい

定数 (const 修飾子)

  • 変数が変更されないことを示すときは、常に使うこと
  • const の位置は型名より前。例: const int foo
  • const な変数を関数へ渡すときは、関数の引数も const でないといけない

キャスト

C言語形式のキャストは使ってはいけない

double d = 3.14;
// int i = (int) d;  // NG
int i = static_cast<int>(d);  // OK

関数

関数の実装

  • 要点をしぼる
  • 行数は少なく。目安は40行程度

関数呼び出し

  • 引数へ渡す値が複雑な式で1行が長くなるとき
    • 一時変数を作ってそこに代入したのを代わりの引数にしていい
      ※ちゃんとした名前にすること
  • 改行する場合は下記のどちらか
    • 後続の行は最初の引数にそろえる
    • スペース4つでインデントした後続行に、引数を書く
bool result = DoSomething(averyveryveryverylongargument1,
                          argument2, argument3);

bool result = DoSomethingDoSomethingDoSomething(
    argument1, argument2,  // スペース4つでインデント
    argument3, argument4);

クラス

クラスのフォーマット

  • public:, protected:, private:
    • インデントはスペース1つ
    • に空行を入れる
    • に空行を入れない
class MyClass : public OtherClass {
 public:  // インデントはスペース1つ
  MyClass();
  // 省略

  // ↓空行を入れる

 protected:
  void SomeFunction();  // ←protectedとの間に空行禁止
  // 省略

 private:
  bool SomeInternalFunction();

  int some_var_;
  int some_other_var_;
};

宣言順

  1. 型(typedef、using、内部構造体・クラスを含む)
  2. 定数
  3. ファクトリ関数
  4. コンストラクタ
  5. 代入演算子
  6. デストラクタ
  7. それ以外のすべてのメソッド
  8. データメンバ

条件文

if文については特に気を付けることはない。

if (xxx) {  // スペースを入れる
  xxx;  // インデントはスペース2つ
}

switch文

インデントと中括弧

switch (var) {
  case 0: {  // スペース2つでインデント
    ...      // スペース4つでインデント
    break;
  } // ←複数行の場合、中括弧が必要
  case 1: {
    // 何もしない場合も中括弧が必要
  }

ループ

ループ内でしか使わない変数は、()内で宣言する。
複数ある場合はループに入る直前に宣言していい。

for (int i = 0; ...; ++i) {

列挙型

ネーミングルール以外は気を付けることはない

/**
 * @brief 比較結果
 */
typedef enum {
  kDifference,  ///< 差分あり
  kNoDifference,  ///< 差分なし
  kInvalid,  ///< 無効な値
} ComparisonResult;

auto

  • autoを使うとき
    • 型の名前が長いとき
      • イテレータやそのほかの長い型名、特にfindやbegin、endの呼び出し時など
    • 型の名前が明確
    • 型の名前が重要でない(=型の名前がコードを読む人の理解の役に立たない場合)
  • autoを使わないとき: 型名を明示することで可読性が向上する場合

コメント

  • 形式
    • ///* .. */ どちらを使ってもOK. ただし、一貫性を持つこと。
    • 行末コメントを入れる場合、コードとの間に2つのスペースを入れる。
  • 冗長なコメントは書かない
    • コメントなしの具体的な変数名 > コメントありの曖昧な変数名
    • 分かっていることをいちいちコメントに書かない
  • コメントを書くべき箇所
    • トリッキーなことをする処理
    • 複雑な処理
    • 明らかでない内容

ヘッダファイル

  • ヘッダファイル単体でコンパイルできること
    • 「*.cppにincludeして初めてコンパイルできる」ではダメ
  • インクルードガードを付けること
    • シンボル名:<PROJECT>_<PATH>_<FILE>_H_
      • PATHはフルパスであること(他の同名ファイルとかぶらないようにするため)
    // foo/src/bar/baz.h のインクルードガード
    #ifndef FOO_BAR_BAZ_H_
    #define FOO_BAR_BAZ_H_
    
    // ここに記載する
    
    #endif  // FOO_BAR_BAZ_H_
    
  • テンプレートやinline関数などの定義は、宣言と同じファイルに含めること
  • 前方宣言は可能な限り避けること。
    • 下記の場合はそのヘッダをincludeすること
      • 別のヘッダで宣言されている関数を使いたい場合
      • 別のヘッダにあるクラステンプレートを使いたい場合
  • inline関数
    • 関数の定義が小さいとき(10行以下)だけ使うこと
      • 特にデストラクタは、暗黙的にメンバのデストラクタと基底デストラクタを呼び出すため見た目より長くなる
    • ループやswitch文のある関数はinline化しても効率よくはならない(コードサイズが小さくなるとか)
  • includeする順番(hoge.cppの場合)
    1. hoge.h
    2. (空行)
    3. Cシステムヘッダ
    4. C++システムヘッダ
    5. (空行)
    6. ほかのライブラリのヘッダ
    7. 自身のプロジェクトのヘッダ
      1. アルファベット順に並べる

その他

  • インクリメント/デクリメント
    • (前置でも後置でも結果が変わらない場合) 前置の形を使用する。つまり ++i

Discussion