Menu

Coding

develop (84)
novice123 ds14050

開発に参加したい方へ>コーディング時の注意点

設計・実装時の注意点

間違いを防ぎソフトの品質を保つために以下の注意点をふまえた上でコーディングを行ってください。

現在のコードの中にはこのルールに従っていない部分があるかもしれませんが、それは(潜在バグでない限り)そのままにしておいてかまいません。ただし、変更を行った後は極力このルールに従うようにしてください。

一般的なコーディングルールに目を通しておくことは非常に有用です。包丁を振り回してはいけないように、言語規約上許されていてもやってはいけないことがあるのがプログラミングというものです。

基本原則

ソースコードは一人だけが編集するのではありません。あなたが直した次の行を別の人が変更するかもしれません。そのとき必ずしも上から下まで全てを見て、全て理解した上で変更する保証はありません。

ミスでも、誤解でも不適切なコードからは不適切な動作しか出てきません。

わかりやすく書く

インデントは周囲にあわせましょう。

80文字を越える場合は行を分割しましょう。C++ではスペースを入れられるところには改行を入れられます。C++では空白で区切って並べられた文字列は1つにまとめられるというルールを利用して、文字列定数も複数行に分けられます。

やろうとしていることを書く

コメントにはどう動くかではなくどうしたいかを書きましょう。そうすることでプログラムとコメントが一致していないときにすぐにバグだと解ります。

また、関数の動作をコメントで明確に規定することで誤った動作への依存や誤解を防ぐことができます。

ありそうな例:

関数を書く→別の人が作者の意図していない動作に依存したコードを書く→関数を意図通り動くように修正する→別の人の作ったところが動かなくなる。

(他人が) 間違いにくく書く

ポインタはnewしたらdeleteしないといけないとかリソースは使ったら解放しないといけないといった制約は最初に書いた人は意識しているかもしれませんが別の人が見落とす可能性は十分にあります。また両者が離れている場合に途中で流れを変えるコードを書く人がいるかもしれません。

できるだけスコープと自動変数の仕組みを利用し、関連する2カ所を同時に変更しないと動かなくなるコードや途中で抜けられると動かなくなるコードは避けましょう。

また見通しを良くし、間違いを防ぐためにも関数のサイズは小さく抑えましょう。

Policyを守る

コードはいくつかのクラスに分かれていますが、ポリシーは同じではありません。ポリシーとしては例えば以下のようなものがあげられます。

  • 他のクラスへの依存性
  • Windowsへの依存性
  • ライブラリへの依存性
  • スレッド動作の安全性 (本エディタでは今のところ不要)
  • 要求されるパフォーマンス
    新規にクラス・関数を追加するときはどのようなポリシーにするかを考えましょう。また、既存のコードを変更するときはポリシーを守るようにしましょう。

一般的な設計時注意事項

プロジェクト固有のコーディングルール

メンバー変数の形式

メンバー変数名は m_ で始める。

その次には型を表す以下の文字列を書く。ポインタの場合にはpをその前に付ける。

  • cクラス名 : クラス
  • n : 整数
  • u : 符号無し整数
  • sz : 文字列
  • h: Windowsから受け取ったハンドル
  • s: string
    識別子はその後に付ける。

例: m_cEditView, m_szFilename

定数名は大文字

変数と区別するために、定数には大文字のみを使いましょう。

for内の変数宣言は使わない(ANSI版)

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を付ける

メンバー変数を操作しないメソッドにはconstを付けましょう。

例:

int GetValue() const;

オブジェクトを渡すときは原則として const OBJ&

参照で渡すのは無駄なコピーを防ぐため、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を使うのは以下のように本当に必要なときだけとし、基本的にはローカル変数を使うようにしてください。

本当に必要なとき

  • スタックサイズに対して巨大なデータを扱うとき。
  • 確保したメモリを呼び出し元に返すとき。
  • Queueのように確保したメモリを後で解放するとき。
  • ポリモーフィズムを使うとき。
    など。これらの条件に当てはまる場合でもスマートポインタの利用を検討しましょう。ただし、コンテナライブラリにauto_ptrは入れられないことに注意してください。

できるだけライブラリを使う

ライブラリ関数と同等の機能を作ってもコードを増やすだけ無駄です。また、行数が増えて見にくく、意図も伝わりにくくなります。

特に文字列操作の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]*/

コンパイラの制限 Ver1.x.x.x(ANSI版)

未サポートの記述があります。

記述 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) 未サポート サポート サポート 列挙型を使用

コンパイラの制限 Ver2.x.x.x(Unicode版)

Visual C++ .NET 2005 Express Editionでコンパイルできるコードであれば問題ありません。

参考リンク

http://sakura-editor.sourceforge.net/cgi-bin/cyclamen/cyclamen.cgi?log=unicode&v=1350

Language C FAQ (Japanese)

Google C++スタイルガイド 日本語訳


Related

Wiki: Introduction
Wiki: Join

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.