Construction of GA将 / その他の工夫

6. その他の工夫

ここでは、他のページでは書いていない細かい部分に言及します。

6.1 アサーション

C++にはassert関数がありますが、これにはいくつか不満な点があります。

  1. アサーションに引っかかった時(条件式がfalseの時)にメッセージを出す機能が無い。
  2. デバッグモード時にしか有効にならない。

Javaのassertはこの辺が融通きき、デバッグ用にメッセージ出せるし、実行時にアサーションの有効/無効を切り替えれます。

という訳で、無ければ作ろうって事で自作しました。大体こんな感じです。

// アサーション設定
// 有効にするなら1を、無効にするなら0を設定する
#define ENABLE_ASSERTION 1

// アサーション用関数
void reportError( const char *functionName,
                  const char *fileName, int lineNumber,
                  std::string message );

// アサーション
#if ENABLE_ASSERTION
#define ASSERT(X,M) if( !(X) ) { reportError( __FUNCTION__,__FILE__, __LINE__, (M) ); }
#else
#define ASSERT(X,M)
#endif // if ENABLE_ASSERTION

(実際には#define ENABLE_ASSERTION 1の行は、デバッグモードなら常に1で、リリースモードなら適当に切り替えるとかって処理をしていますが。)

例えばASSERT( x <= 9, "xが9より大きいです。" );と書いておくと、条件が成り立たない場合は、関数名・ファイル名・行数と共にメッセージが出力されます。

で、このアサーションを使って、まずはデバッグモード・アサーション有効で走らせて、その後リリースモード・アサーション有効で更にテストするとかって事をしています。 また、ASSERTマクロの他にASSERTL(軽いアサーション。速度的にクリティカルでない部分で使い、基本的に常に有効)とかASSERT_HEAVY(重いアサーション。基本的にデバッグモード時のみ有効)とかも作りました。

アサーションは結構有効で、デバッガで一通り動作を見ても発見出来なかったバグが見つかる事もありました。まぁ、アサーションを過信するのも禁物ですが、実装しておいて損は無いと思います。

6.2 範囲チェック配列

またJavaの話になりますが、Javaの配列は添字が配列の範囲内に収まっているかチェックして、範囲外なら例外投げてくれます。これと同じ事をしたくて、範囲チェック配列を作りました。実装は下記の様になっています。

// 自作の配列もどき。
// 引数SIZE 格納可能な要素数。
// 引数T    各要素の型。
template <size_t SIZE, typename T> class MyArray {

private:
	// 配列の実体
	T valueArray[ SIZE ];

public:
	// 領域確保だけ行う。
	// 「デフォルト値」で無条件に初期化したりとか、そんなJavaの配列みたいに
	// 気の利いた機能は無いんで注意。
	MyArray(){ /* NOP */ }

public:
	// 領域解放を行う。
	~MyArray() { /* NOP */ }

public:
	// index番目の要素を取得する。
	// インデックスが範囲外の場合の動作は未定義なんで注意。
	T& operator[]( const size_t index ) {

		ASSERT( index < SIZE, "範囲異常 index==" + toStringST( index ) );

		return this->valueArray[ index ];

	}// operator[](size_t)

public:
	// このインスタンスの長さ(格納可能な要素数)を取得する。
	size_t length() const {

		return SIZE;

	}// length()

};// MyArray

実装にあたってはGPS将棋さんのCArray(こちらのp.30)を参考にしましたが、テンプレート引数の順番は変えています。 これは、二次元配列を作る際に、私の実装ならMyArray<2,MyArray<8,int>> hoge;という感じに、配列長を書く順番がC++標準の配列と同じに出来るからです。

アサーションを有効にしておけば範囲チェックが動作するんで、結構便利です。自殺手を放置して王様が取られた(駒台に乗せようとした)バグを発見したりとかって事もあります。

ただ、クラス名が長いので3次元とか4次元の配列にすると、コードが無駄に長くなります。短縮してMAとかにしても良かったんじゃないかなぁ…と、時々思います。