最終更新日 2024-09-25

HD.version.SDK よくあるフリーズ

よくあるフリーズのパターン

ここでは良くあるフリーズのパターンについて、
紹介します。

このページに記載されるのはフリーズするサンプル このページではよくあるフリーズと、その追い方を学ぶので、
サンプルを実行するとフリーズするものが大半です。

よくあるフリーズの例①

圧倒的によくあるフリーズの例。
それは「○○->配列[ix]」のような、配列にアクセスする際、
ixの値をチェックしていないため、「配列外アクセスエラー」になり、即フリーズする、というものです。

1534年のシナリオを選択すると、上杉謙信が存在しないのでエラー
void 天翔記クラス::On_シナリオ選択直後(String^ シナリオファイル名) {
  // 長尾景虎の列伝の人物が存在しない場合、iBushouIDには0xFFFFが返ってくる。
  int iBushouID = 武将->Find_武将番号(列挙::武将::列伝番号::長尾景虎);

  // 配列は0~531の範囲でアクセスしなければならない。0xFFFFなど、範囲外でアクセスすると、即座にフリーズする。
  デバッグ出力 << 武将->配列[iBushouID]->姓名 << endl;
}

try...catchで囲んで、エラーを出す。

上のようなフリーズの場合に行うのは、try ... catch で
イベントハンドラを囲む、というものです。

try...catchで囲み、エラーメッセージをModDebuggerに表示
void 天翔記クラス::On_シナリオ選択直後(String^ シナリオファイル名) {
  try {

    int iBushouID = 武将->Find_武将番号(列挙::武将::列伝番号::長尾景虎);

    デバッグ出力 << 武将->配列[iBushouID]->姓名 << endl;

  } catch (Exception^ e) {
    デバッグ出力 << e->Message << endl;
  }
}

範囲を判定して正しく直した
void 天翔記クラス::On_シナリオ選択直後(String^ シナリオファイル名) {

  int iBushouID = 武将->Find_武将番号(列挙::武将::列伝番号::長尾景虎);

  if ( 0 <= iBushouID && iBushouID < 武将->配列->Count ) {
    デバッグ出力 << 武将->配列[iBushouID]->姓名 << endl;
  }

}

又、「○○->配列」の範囲内にあるのかないのかを調べるのは、
以下のように「Is_Contains」を利用できます。

範囲を判定して正しく直した
void 天翔記クラス::On_シナリオ選択直後(String^ シナリオファイル名) {

  int iBushouID = 武将->Find_武将番号(列挙::武将::列伝番号::長尾景虎);

  // Is_Containsの「1番目の引数と2番目の引数」は、どちらが先でも後でもよい。
  if ( Is_Contains( iBushouID, 武将->配列 ) {
    デバッグ出力 << 武将->配列[iBushouID]->姓名 << endl;
  }

}

よくあるフリーズの例②

少し慣れてきたころによくある例、
それが、.NETではお馴染みの「gcnewしていないマネージ参照のプロパティに値を突っ込んでいる」というものです。

シナリオを選択すると、未初期化のposに値を突っ込んでるのでフリーズ
void 天翔記クラス::On_シナリオ選択直後(String^ シナリオファイル名) {

  // すべての城の位置は城位置型。
  城位置型^ pos;
  pos->X = 255;
  pos->Y = 255;

  // 全ての城を見えないはるかに範囲外の右下にもっていく
  for each (auto c in 城->配列) {
    c->位置 = pos;
  }

}

同様にtry...catchで囲むと、下記のようなエラーとなる。

正しく直すには、gcnewする必要があります。

gcnewして正しく直した
void 天翔記クラス::On_シナリオ選択直後(String^ シナリオファイル名) {

  // すべての城の位置は城位置型。
  城位置型^ pos = gcnew 城位置型();
  pos->X = 255;
  pos->Y = 255;

  // 全ての城を見えないはるかに範囲外の右下にもっていく
  for each (auto c in 城->配列) {
    c->位置 = pos;
  }

}

その他

以上が「よくあるフリーズ」の例となります。