開発に参加したい方へ>コーディング時の注意点
間違いを防ぎソフトの品質を保つために以下の注意点をふまえた上でコーディングを行ってください。
現在のコードの中にはこのルールに従っていない部分があるかもしれませんが、それは(潜在バグでない限り)そのままにしておいてかまいません。ただし、変更を行った後は極力このルールに従うようにしてください。
一般的なコーディングルールに目を通しておくことは非常に有用です。包丁を振り回してはいけないように、言語規約上許されていてもやってはいけないことがあるのがプログラミングというものです。
ソースコードは一人だけが編集するのではありません。あなたが直した次の行を別の人が変更するかもしれません。そのとき必ずしも上から下まで全てを見て、全て理解した上で変更する保証はありません。
ミスでも、誤解でも不適切なコードからは不適切な動作しか出てきません。
インデントは周囲にあわせましょう。
80文字を越える場合は行を分割しましょう。C++ではスペースを入れられるところには改行を入れられます。C++では空白で区切って並べられた文字列は1つにまとめられるというルールを利用して、文字列定数も複数行に分けられます。
コメントにはどう動くかではなくどうしたいかを書きましょう。そうすることでプログラムとコメントが一致していないときにすぐにバグだと解ります。
また、関数の動作をコメントで明確に規定することで誤った動作への依存や誤解を防ぐことができます。
ありそうな例:
関数を書く→別の人が作者の意図していない動作に依存したコードを書く→関数を意図通り動くように修正する→別の人の作ったところが動かなくなる。
ポインタはnewしたらdeleteしないといけないとかリソースは使ったら解放しないといけないといった制約は最初に書いた人は意識しているかもしれませんが別の人が見落とす可能性は十分にあります。また両者が離れている場合に途中で流れを変えるコードを書く人がいるかもしれません。
できるだけスコープと自動変数の仕組みを利用し、関連する2カ所を同時に変更しないと動かなくなるコードや途中で抜けられると動かなくなるコードは避けましょう。
また見通しを良くし、間違いを防ぐためにも関数のサイズは小さく抑えましょう。
コードはいくつかのクラスに分かれていますが、ポリシーは同じではありません。ポリシーとしては例えば以下のようなものがあげられます。
メンバー変数名は m_ で始める。
その次には型を表す以下の文字列を書く。ポインタの場合にはpをその前に付ける。
例: m_cEditView, m_szFilename
変数と区別するために、定数には大文字のみを使いましょう。
C++では for( int i = 0; i < 10; ++i ) とforの()内で変数を宣言することが出来ます。しかし、MS Visual C++ 6とBorland C++ 5.5で宣言された変数のスコープが異なるために同一変数名で2回使おうとするとどちらか片方でしかコンパイルできなくなってしまいます。
#define for if(0);else for
とすることでVisual C++でもスコープをループ内に制限することが出来ますが、とりあえずこれは使わないことにします。
変数を宣言した時点では中身は不定です。0ではありません。
関数内で配列変数を初期化と同時に宣言した場合、変数領域への値の設定が変数の初期化の度に行われます。サイズの大きな配列を自動変数として宣言すると実行速度に影響が出ます。
関数内で使われるテーブルなど静的な変数でも問題がないものについてはstaticを付けてください。
1つの関数で200行を越えるようであれば分割を検討してください。特にswitch~case文でcase内に処理を直接書いてしまうと1つの関数が肥大化しすぎる傾向にあります。
必要な定数は定数として定義して使うようにし、コード中に直接書かないでください。直接書いてしまうとその値の意味するところが後でわからなくなったり、後で値を変更したいときに変更漏れが発生したりすることになります。
定数名にはその値の意味がわかる文字列を使ってください。
複数のメソッド内のみで用いられる変数をメンバー変数として定義することは行わなず、それぞれの関数で宣言してください。
メンバー変数はオブジェクトの「状態」を保持するもので、一時変数はこれに該当しません。また、同じ変数を使い回すと初期化漏れの検出が困難になります。
別の関数を呼び出すとき、必要な値は引数で渡すようにしてください。
同一クラス内で複数の処理を行うためにあるメソッドから別のメソッドを呼び出す場合にも、呼び出される処理が汎用的なものの場合はメンバー変数を引数として渡すようにして、直接メンバー変数を操作する関数を制限するようにしてください。
メンバー変数を操作しないメソッドにはconstを付けましょう。
例:
int GetValue() const;
参照で渡すのは無駄なコピーを防ぐため、constは書き換えを防止するためです。
上と逆ですが、戻り値の型を参照として宣言した上で一時変数をreturnで返すとスタック破壊を引き起こします
クラスを作るときには丸ごとコピーされる場合を考慮してください。デフォルトのコピーコンストラクタではすべてのメンバーが複写されますが、ポインタを含むなどそれでは都合の悪いときはコピーコンストラクタ、代入演算子を定義しましょう。
よく似た処理をループにて処理する場合、switch~case文で各処理がそれぞれ1回ずつ行われるようなコーディングはわかりにくいので避けてください。
悪い例:
for( i =0; i < 3; ++i ){ switch(i){ case 0: 処理1; break; case 1: 処理2; break; case 2: 処理3; break; } }
これは処理1; 処理2; 処理3; と同じなのでループにする必然性がありません。
テーブルのデータを1つずつ処理するような場合のみループを使うべきです。
switch(ループ変数) という箇所があったらまずこのパターン。書き換えを検討しましょう。
newによってメモリを動的に確保した場合はdeleteによって解放する必要があります。しかし、プログラムが複雑になってきたりエラー処理が途中に入ったり 例外が発生したりするとdeleteが忘れられる危険性があります。
newを使うのは以下のように本当に必要なときだけとし、基本的にはローカル変数を使うようにしてください。
本当に必要なとき
ライブラリ関数と同等の機能を作ってもコードを増やすだけ無駄です。また、行数が増えて見にくく、意図も伝わりにくくなります。
特に文字列操作のC標準関数とSTLライブラリには目を通してできるだけ再利用するようにしましょう。
Windows APIにも高機能なAPIが多数あります。(多数なだけに見つけるのが大変ですが...)。
Unicode版限定です。
Funccode_define.h/Funccode_enum.hは、Funccode_x.hsrcから自動生成されるファイルです。
HeaderMake.exeは、Funccode_define.h/Funccode_enum.hのファイルの日付がFunccode_x.hsrcより古いときにファイル生成を行います。直接編集すると正しく動作しません。
Funccode_define.h/Funccode_enum.hは、直接編集しないようにしましょう。
インクルードガードは下記のような感じで入れるとよいです。
インクルードガードの挿入(GUID使用)マクロがあり、Ver2.x.x.x(UNICODE版)で使われています。
/* Copyright (C) **YEAR**, **AUTHOR** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef SAKURA_SAMPLE_FA8955FC_6B99_431C_B973_4487CEA75D4A9_H_ #define SAKURA_SAMPLE_FA8955FC_6B99_431C_B973_4487CEA75D4A9_H_ #endif /* SAKURA_SAMPLE_FA8955FC_6B99_431C_B973_4487CEA75D4A9_H_ */ /*[EOF]*/
未サポートの記述があります。
記述 | Visual C++6.0 | Visual Studio.NET | Borland C++ Compiler 5.5.1 | 対応 |
---|---|---|---|---|
std::max(), std::min() | 未サポート | サポート | サポート | t_min(), t_max()を使う(別途マクロを定義している) |
#pragma once | サポート | サポート | 未サポート(無視) | #ifndef~#define~#endifを使う |
_countof() | サポート | サポート | 未サポート | 別途マクロを定義しているので使用可能 |
static const変数初期化(class) | 未サポート | サポート | サポート | 列挙型を使用 |
Visual C++ .NET 2005 Express Editionでコンパイルできるコードであれば問題ありません。
http://sakura-editor.sourceforge.net/cgi-bin/cyclamen/cyclamen.cgi?log=unicode&v=1350