質問
私はゲームに取り組んでおり、現在入力を処理する部分に取り組んでいます。ここには 3 つのクラスが関係しています。 ProjectInstance
レベルなどを開始するクラスがあります。 GameController
入力を処理します。 PlayerEntity
これは、によって決定されたコントロールの影響を受けます。 GameController
. 。レベルを開始すると、ProjectInstance は GameController
, 、そしてそれを呼び出します EvaluateControls
Step メソッド内のメソッド。ゲーム ループ内で呼び出されます。の EvaluateControls
メソッドは次のようになります。
void CGameController::EvaluateControls(CInputBindings *pib) {
// if no player yet
if (gc_ppePlayer == NULL) {
// create it
Handle<CPlayerEntityProperties> hep = memNew(CPlayerEntityProperties);
gc_ppePlayer = (CPlayerEntity *)hep->SpawnEntity();
memDelete((CPlayerEntityProperties *)hep);
ASSERT(gc_ppePlayer != NULL);
return;
}
// handles controls here
}
この関数は正しく呼び出され、アサートはトリガーされません。ただし、この関数が呼び出されるたびに、 gc_ppePlayer
NULL に設定されます。ご覧のとおり、これはスコープ外になるローカル変数ではありません。唯一の場所 gc_ppePlayer
NULL に設定できます。コンストラクター内か、場合によってはデストラクター内にありますが、どちらも呼び出しの間に呼び出されません。 EvaluateControls
. 。デバッグ時、 gc_ppePlayer
返される前に、正しい期待値を受け取ります。もう一度 F10 キーを押し、カーソルが右中かっこにあると、値が 0xffffffff に変わります。ここで困っているのですが、どうしてこんなことが起こるのでしょうか?誰でも?
解決
リリースまたはデバッグ構成をデバッグしていますか?リリースビルド構成では、デバッガーに表示される内容が常に正しいとは限りません。最適化が行われ、これにより、ウォッチウィンドウに、見ているような奇妙な値が表示される可能性があります。
実際にASSERTがトリガーされていますか? ASSERTは通常、リリースビルドからコンパイルされるため、リリースビルドをデバッグしているので、ASSERTがアプリケーションを終了させないのはなぜでしょうか。
ソフトウェアのデバッグバージョンをビルドし、gc_ppePlayerが実際にNULLかどうかを確認することをお勧めします。本当にそうである場合は、このポインターがオーバーライドされているメモリヒープが破損している可能性があります。しかし、それがメモリ破損である場合、一般的にあなたが説明しているよりもはるかに決定論的ではありません。
余談ですが、このようなグローバルポインタ値を使用することは、一般的に悪い習慣と見なされます。本当に単一のオブジェクトであり、グローバルにアクセスする必要がある場合、これをシングルトンクラスに置き換えることができるかどうかを確認します。
他のヒント
gc_ppePlayer == NULL
にウォッチポイントを設定します。その式の値が(NULLまたはNULLに)変更されると、デバッガーは正確に発生した場所を示します。
それを試して、何が起こるか見てみましょう。終了していない文字列、または小さすぎるメモリへのコピーなどを探します...通常、グローバル/スタック変数がランダムに上書きされる問題の原因です。
VS2005にウォッチポイントを追加するには(broneによる指示)
- [ブレークポイント]ウィンドウに移動
- 「新規」をクリック
- [データブレークポイント]をクリックします。入力
[アドレス]ボックスに&amp; gc_ppePlayer
を残します 他の値のみ。- 次に実行します。
gc_ppePlayer
が変更されると、 ブレークポイント ヒットします。 &#8211;骨折
最初に考えたのは、SpawnEntity()が「クリア」された内部メンバーへのポインターを返しているということです。 memDelete()が呼び出されたとき。ポインターが0xffffffffに設定されているかどうかはわかりませんが、memDelete()の呼び出し中に発生した場合、ASSERTが起動しない理由を説明します-0xffffffffはNULLと同じではありません。
コードベース全体を再構築してからどれくらい経ちましたか?このようなメモリの問題は、ソリューション全体を再構築するだけで解決されることがたびたびあります。
関数の最後でステップオーバー(F10)の代わりに(F11)にステップしてみましたか?この例ではローカル変数を表示していませんが、単純にするために一部を省略した可能性があります。そうである場合、F11は(願わくば)それらの変数のデストラクタにステップインし、それらのいずれかが問題を引き起こしているかどうかを確認できるようにします。
「コアにファンダンゴ」があります
動的初期化は、メモリの各種ビット(sic)を上書きします。
グローバルが直接または間接的に上書きされています。 ヒープに対するメモリ内のグローバルはどこですか?
バイナリは、問題がなくなるまで動的に初期化された部分を切り刻みます。 (再帰的に半分ずつコメントアウトします)