ホームへ戻る

6章. 致命的エラーの対応

 コーディングしているとどうしようもないエラー処理をかかなければならないことがあります。
「こんな値来る想定で作ってないからここでもしこの値が来たら強制的に終了するしかない」そんなことがあります。
そんな時無理やり処理を続行してセグメンテーション違反を起こして強制終了するようなプログラムはあるべきではありません。
どうしてもそのような状態になった時は、どこで何故そのようなエラーが起きたのか画面の表示するようにしてみます。
勘の良い方はもう既にプロジェクトの中にError.h/cppというファイルが入っていたことに気付いたかもしれません。
Error.hにはこのような実装をしています。


Error.h


#pragma once

#include <Windows.h>

class Error
{
public:
	static void finish(char* errorMessage, LPCTSTR lpszFuncName, int lineN);
};

Error.cpp


#include "Error.h"
#include <string>
#include <DxLib.h>
#include "Define.h"

using namespace std;

void Error::finish(char * errorMessage, LPCTSTR lpszFuncName, int lineN)
{
	char funcName[1024];
	sprintf(funcName, "%s", lpszFuncName);
	printfDx("異常が発生しました。\n%s\n%s(%d)"
		,errorMessage
		,funcName
		,lineN
	);
	while (!ProcessMessage()) {
		ClearDrawScreen();
		ScreenFlip();
	}
	DxLib_End();
	exit(99);
}

エラーが起きた時にこのメソッドを呼び出すようにします。
これが呼ばれると、errorMessageの文字列が、エラーが起こった「クラス::関数名(行番号)」の情報と共に表示されます。
先に実行結果をお見せします。


このような表示となります。
バグが起きた時にも助けになりますし、テストプレイしてもらっている方やエンドユーザーにも分かりやすいです。
この情報をテキストファイルに落として、それをユーザーから報告してもらうようにしても良いでしょう。
自前サーバーにこの情報を送信するようにしても良いかもしれません。

while文でぐるぐる処理が回っており、ウィンドウを×ボタンで閉じると終了します。
ここでProcessMessage()をちゃんとwhileで回してあげないとウィンドウがフリーズしてしまうので注意してください。

で、前述の、見慣れぬlpszFuncNameとlineNですが、これをわざわざ引数にするのは面倒なのでマクロにします。


Macro.h


#pragma once

#include "Error.h"
#include <DxLib.h>

#define ERR(str) Error::finish(str,_T(__FUNCTION__),__LINE__)

windows.hかDxLib.hをincludeしておけばこのような形でクラス名::関数名や行番号が渡せます。
このマクロの呼出元はそんなことを意識する必要はありません。
呼出元を見てみましょう。


Looper.cpp


#include "Looper.h"
#include "TitleScene.h"
#include "Error.h"
#include "GameScene.h"
#include "Macro.h"

using namespace std;

Looper::Looper()
{
    Parameter parameter;
    _sceneStack.push(make_shared<TitleScene>(this, parameter)); //タイトル画面シーンを作ってpush
}
/*!
@brief スタックのトップのシーンの処理をする
*/
bool Looper::loop() const
{
    _sceneStack.top()->update();    //スタックのトップのシーンを更新
    _sceneStack.top()->draw();      //スタックのトップのシーンを描画
    return true;
}

/*!
@brief シーン変更(各シーンからコールバックされる)
@param scene 変更するシーンのenum
@param parameter 前のシーンから引き継ぐパラメータ
@param stackClear 現在のシーンのスタックをクリアするか
*/
void Looper::onSceneChanged(const eScene scene, const Parameter& parameter, const bool stackClear)
{
    if (stackClear) {//スタッククリアなら
        while (!_sceneStack.empty()) {//スタックを全部ポップする(スタックを空にする)
            _sceneStack.pop();
        }
    }
    switch (scene) {
    case Title:
        _sceneStack.push(make_shared<TitleScene>(this, parameter));
        break;
    case Game:
        _sceneStack.push(make_shared<GameScene>(this, parameter));
//        break;
    default:
        ERR("あるはずのないシーンが呼ばれました");
        break;
    }
}

今回追加したのは
ERR("あるはずのないシーンが呼ばれました");
の部分です。通常は起きないエラーなので、わざとその一行上のコードをコメントアウトしてエラーが発生するようにしてあります。

こうすることで自動的に欲しい追加情報が付加されて表示されるようになります。

→分からないことがあれば掲示板で質問して下さい


HPトップへ 質問掲示板へ

- Remical Soft -