ゆん

プログラム班?

バグを減らす為に

バグを減らす為に有用だと思うことを書いておきます。

サークル内の需要的に考えて主にC++について。

スタイルを守る

コード内では一貫した記述をしましょう。

Google C++スタイルガイド 日本語訳などのようにネット上に色々な見本となるスタイルが記載されています。

インデントは適切に

インデントをいれるだけで構造が格段にわかりやすくなります。

たとえHTMLなどでも以下のようにインデントを入れることで入れ子構造のレベルが一目でわかるようになります。

<table>
	<caption>表1: 入力電圧と出力電圧の測定結果</caption>
	<thead>
		<tr><th>入力電圧(V)</th><th>出力電圧(V)</th></tr>
	</thead>
	<tbody>
		<tr><td>0.430</td><td>3.995</td></tr>
		<tr><td>0.549</td><td>3.975</td></tr>
	</tbody>
</table>

予防的プログラミング

人間は必ずミスをするものです。しかしその確率を減らすことはできます。

紛らわしい変数名をつけない

どうせ入力補助機能に頼るんですからわかりやすくほどほどに長い名前にしましょう。

紛らわしい変数名の例

  • aやbなどといった短く意味のわからない名前
  • 混同しやすい変数名。例、悪: key1, key2, data, date、良: keyOne, keyTwo, data, date_time

曖昧なif

if文による条件分岐によって実行される文が一つの文であるとき、以下のように中括弧を省略することができます。

if((n & 1) == 0) 
	std::cout << "n は偶数です。" << std::endl;

しかし、このif文で実行される命令がいつまでも一つとは限りません。またelseが追加されることもあります。 こういったときに起こりがちなバグが中括弧の入れ忘れです。この対策として下の例のように常に中括弧を入れるというものがあります。

if((n & 1) == 0)
{
	std::cout << "n は偶数です。" << std::endl;
}

また同様にenumを使う際にも最後の定数名の後に","をつけることで追加したときに","を忘れてもコンパイルエラーが出なくなります。

マジックナンバーを使わない。

ソースコード中に突然出てくる定数のことをマジックナンバーといいます。 たとえばキャラクターの移動などを制限するため以下のようなコードを書くことが良くあると思います。

if (value < 0)
{
	y = 0;
}
else if (value > 480)
{
	y = 480;
}
else
{
	y = value;
}

このとき 0 や 480 などがマジックナンバーであり、(定数)変数で置き換えるべきものです。これらの定数を変数で置換することによって、定数の変更忘れがなくなります。

const int minY = 0;
const int maxY = 480;

if (value < minY)
{
	y = minY;
}
else if (value > maxY)
{
	y = maxY;
}
else
{
	y = value;
}

解放後のポインタにはNULLを代入する

mallocやnewなどで確保した領域のポインタに対して多重にfreeやdeleteを行うことは許されていません。

解放した後のポインタには必ずNULLを代入すべきです。NULLに対してfreeやdeleteを行っても何も起こりません。 以下のようなマクロを使うことで簡単に記述できます。

#define DELETE(p)       { delete(p);     (p) = NULL; }

マクロの使用を控える

#defineなどのマクロはエラーメッセージがわかりづらく、理解しがたいバグを引き起こす可能性があるのであまり使わないようにしましょう。

#defineの変わりに定数変数を使うことで、エラーメッセージの中にその変数名がでてきてデバッグしやすくなります。

古いコードの管理

一部の処理を書き換えたときに,以前のコードをコメントアウトなどで残しておくのは危険.

どんどん不要なコードが増えていくのでわけがわからなくなります

かといって以前のコードをコピーしてバックアップしていくのも大変です.

バージョン管理のすすめ

コードの変化を管理するためには,バージョン管理ソフトが便利です.

以下のような機能があります・

  • 各時点でのソースコードのバックアップ
  • バージョンごとのコメント付け
  • 過去のバージョンとの比較

gitやsubversionなどを入れて,TortoiseGitなどのGUIツールを入れれば使いやすいです.

分割コンパイル

一つのファイルにすべてを記述するのではなく機能ごとや処理対象ごとにソースコードを分割します。

基本的なやり方

  • ヘッダファイル(.h)には外部で使う関数宣言、マクロ定数の定義、外部(external)変数宣言、構造体、クラスの定義などを記述します。
  • ヘッダファイルでないソースコード(.cppなど)には#includeや関数定義、変数宣言、構造体、クラスの定義などを記述します。
  • 通常main以外のファイルでは.cppと.hを1対1対応させておきます。

車輪の再発明をしない

文字列に対する処理などは、思ったよりも多くの関数が標準で用意されています。

同等の機能を自分で新たに書き直すのではなく、可能な限り標準の関数を利用するようにしましょう。

std::swap、std::max、std::maxなどはすぐにでも使える便利な関数だと思います。

ポインタの使用を控える

C や C++ においてポインタの扱いは非常に難しくバグの温床となっています。なので可能な限り使わないべきだと思います。

スマートポインタ

C++にはスマートポインタと呼ばれる自動的にdeleteを呼び出してくれるポインタがあります。

auto_ptrやshared_ptrなどの種類があります。 後者はBoostライブラリを導入することで使えるようになりますが、Visual Studio2008からは標準のライブラリの中に含まれるようになりました。

スマートポインタ使用例(Visual Studio2008以前)

#include <iostream>
#include <memory>

class Destructable
{
public:
	Destructable(){}
	~Destructable()
	{
		std::cout << "Object is Destructed." << std::endl;
	}
};

int main()
{
	const std::auto_ptr<Destructable> smart_ptr(new Destructable());

	return 0;
}

スマートポインタ使用例(Visual Studio2008以降)

#include <iostream>
#include <memory>

class Destructable
{
public:
	Destructable(){}
	~Destructable()
	{
		std::cout << "Object is Destructed." << std::endl;
	}
};

int main()
{
	std::tr1::shared_ptr<Destructable> smart_ptr(new Destructable());

	return 0;
}

参照(リファレンス)

C++には参照という機能があります。これは変数の種類の一つであり、ポインタを直接操作することなく、参照先の変数の値を変更することができます。

下記にポインタを使ったswap関数を示します。

void swap(int *a, int *b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}

以下に参照を使ったswap関数を示します。

void swap(int &a, int &b)
{
	int temp = a;
	a = b;
	b = temp;
}

関数の引数名の前に"&"をつけることでポインタを使うことなく同等の機能を利用することができます。

配列は使わない

基本的に配列を使うよりはVector(可変長の配列)を使ったほうが良いです。 その他STLには便利なコンテナやアルゴリズムがたくさんあります。

関数ポインタよりはクラス

関数ポインタを使うよりも継承を用いたほうが安全です。


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-11-21 (木) 11:25:35 (1617d)