GaitGeneration by Graph Search
|
今後このソースファイルを使う人のためにC++で大きなプロジェクトを作成するときのルールをここに定義 しておく. 基本的には google c++ style guide に従っているが,一部独自のルールを追加している.
独自ルールについて,
命名規則について
クラスについて
関数について
定数について
ヘッダーについて
配列について
for文について
小数について
列挙体について
構造体について
変数やクラスの名前を決めるときは下記のどれかを使って決めるのが基本となる. 例えば int NumBer; とか class Sample_Class;だとかは避けること.
Google C++ Style Guideでは,以下のように命名することが推奨されている.
また,変数名をローマ字で書いたり,過度に省略したりするのは控えるべき. (例えば int sushi; とか std::string tkg;など.寿司は仕方ないが...) 固有名詞は全部書く,逆に init (初期化)や num (ナンバー)などよく使うものは省略すべき. func(関数)等は見ればわかるので書かないように CalcFunc() → Calc() 多少長くなっても何しているか分かりやすいほうが見やすなる.(特に関数において).
よく使う省略語
関数においては動詞→目的語となるように付けること.(例えば GetData() とか MakeMap() とか) また,bool型の場合は質問形式で命名するとよい. bool is_empty = false; とか bool IsOddNumber(const int num); など.
なぜこのような命名規則を導入するのかというと, 自分の書いたプログラムを他人に読んでもらうとき, 命名方法が適当だと非常に読みづらくなるためである.
基本的にメンバ変数は全て private: に入れておくこと. 面倒だが,値をとったり設定したりしたいなら,Get??? や Set??? 関数を作って,それを使うこと.
生のメンバ変数の値を変更するのはやめるべき.
また,一つのクラスに大量の機能を追加しないこと. かつての PassFinding クラスはグラフ探索+ファイル入出力+コマンド送信等 多量の機能を持っていたが,可読性が下がるのであまりよくない. 機能を細かく分けてプログラムを書くべき.
関数を宣言した場合,その関数の引数や機能についてコメントを付けること. 後から見た時に何をすればよいか分かりやすくてプログラムが楽になる. 注釈はヘッダーに書いておけば,他のファイルでも確認できるようになる.
値を返したいときは基本は戻り値を使うこと. 不必要なポインタ渡しや参照渡しはプログラムを無駄に煩雑にするため,避けるべき. 複数の値を返す場合は,ポインタ渡しを用いて値を返すようにし, 簡単な処理の場合は tuple を使うこと.
また変更しない引数は const を付けておくこと.
同様にメンバ変数を変更しないメンバ関数にも const を付けること.
関数の引数においてマジックナンバーは避けること. マジックナンバーとは直に数値を使うことで, 本人以外にその値が何を表しているのか理解できないものを指す. 変数や列挙体やコメントなどを用いて変数の意味を説明するようにすること.
#define を使うのはやめること. C++においては const static な変数(静的で定数のメンバ変数)を使うほうがよい.
C++には constexprという機能があり,これを使うとコンパイル時に定数を計算してくれるため, 実行時の負荷が減る. 使用可能であるならばこれを使うべき.
C言語において通常使われる int _array[10]; のような配列の使用は最小限にしたほうが良い. なぜなら,このプログラムでも過去にそれによるスタックオーバーフローが起きていたためである. (time[1000]という配列に時間を記録していたため, 1000回以上のループができなくなっていた.) とりあえず大きな配列を作っておいて,その中にデータを記録するのは拡張性が低いし, 見つけづらいバグの温床になるため, std::vector (動的な配列) を積極的に使うことを推奨する.
new/delete は個人的には絶対に使いたくない.なぜならば,メモリリークの温床になるからである. 動的配列は vector や map などのコンテナを使うこと.
また,変数を int x1,x2,x3,x4;のように大量に宣言するのはやめること. その場合は普通に配列で構わない.
あるいは,std::arrayを使うこと,std::array<int, 4> x;
for文に使用する変数は i → j → k とすること.通例そのような命名をすることが多いためである. また,for文の中でサイズの大きなクラスや構造体を宣言するのはやめること. 非常に負荷がかかるためである.
必ず,インクルードガードを書くこと.#ifndef ~ #endifのこと. #pragma once と書くと,インクルードガードを書かなくてもインクルードガードの機能が働く. しかし,これはC++の機能ではないので非推奨.(実際にはほとんどのコンパイラで使えるが, 一部のコンパイラでは使えない.特にこだわりがないならばどちらを使ってもよい.)
ヘッダーにはむやみに #include を書かないようにすること. コンパイル時間が伸びるためである.過不足なく必要なものだけをインクルードするようにする. またグローバル変数を使ったり,externを使ったりするのは避けること. 多くの場合スパゲッティコードの原因になる. 設計をよく考えれば使わずに済むはず.どうしても必要な場合は一つのヘッダにまとめておくこと. 散らされると探すのが本当に大変になる.
小数をあらわす事のできる変数の形は float と double の2つがある. float のほうがサイズが小さいので探索に向いている,floatで統一して書いていく.
float = 4byte,double = 8byte.
整数型の引数を使って関数の機能を分けたいとき,例えば以下のような関数を使いたいとき,
このような場合は列挙体を使うことをお勧めする. 何故ならば,読みやすくなり,不正な値を入力されづらくなるためである. 例えば以下のように書き換えることができる.
C++で書かれているのでわざわざ typedef しなくてもよい. C++においては struct はクラスと同じ扱いになる. (ただし,デフォルトのアクセス指定子が異なる.クラスは private,structは public )
そのため,structを継承したクラスを作ることもできる.(非推奨だが)
構造体を使用する場合は,メンバ変数は全て public にしておき, そのようなクラスを作成したい場合に構造体を使うとよい.