2009-03-02 7 views
1

私はゲームに取り組んでいます。私は現在、入力を処理する部分に取り組んでいます。ここには3つのクラスがあり、レベルを開始するProjectInstanceクラスがあり、入力を処理するGameControllerと、GameControllerによって決定されるコントロールの影響を受けるPlayerEntityがあります。レベルを開始すると、ProjectInstanceはGameControllerを作成し、ステップメソッドでEvaluateControlsメソッドを呼び出します。これはゲームループ内で呼び出されます。 EvaluateControls方法は、ビットのようになります。ポインタが不思議にNULLにリセットされる

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に変わります。私はここに迷っています、どうすればこのことが起こりますか?誰でも?

答えて

2

リリースまたはデバッグの設定をデバッグしていますか?リリースビルド構成では、デバッガで表示される内容が常に正しいとは限りません。最適化が行われます。これにより、見ているようにウォッチウィンドウに気まぐれな値が表示されるようになります。

実際にASSERTトリガーが表示されていますか? ASSERTは通常、リリースビルドからコンパイルされるため、ASSERTがアプリケーションを終了させない理由はリリースビルドをデバッグしていると思います。

ソフトウェアのDebugバージョンをビルドし、gc_ppePlayerが本当にNULLかどうかを確認することをお勧めします。実際には、もしこのポインタがオーバーライドされているようなメモリヒープの破損を見ているかもしれません。しかし、それが記憶腐敗の場合、一般的にあなたが記述しているよりも決定論的ではありません。

このようにグローバルポインタ値を使用することは、一般的に悪い習慣とみなされます。本当に単一オブジェクトであり、グローバルにアクセス可能である必要がある場合は、これをシングルトンクラスに置き換えることができるかどうかを確認してください。

+0

+1最初の部分については、ちょうど私が言うつもりだったが、シングルトンは、私の本の中のパターン)単純なインスタンス化と参照/ポインタはよりモジュール化されています。 –

+0

@ロバート - シングルトンは誤用されるとアンチパターンになる可能性があります。これはよくあるケースです。オブジェクトが本当にシステム内の単一のオブジェクトであり、合法的に1つ以上のものが存在することは決してありませんが、シングルトンパターンは使用するのに最適ですか?生のポインタ/リファレンスよりも優れています。 – LeopardSkinPillBoxHat

+0

..IMHO、少なくともあなたはそれへのアクセスを追跡することができます。 – LeopardSkinPillBoxHat

5

gc_ppePlayer == NULLの式の値が(NULLまたはNULLに)変更されたときにウォッチポイントを設定すると、デバッガは正確に発生した場所を示します。

何が起こるかをご覧ください。終了していない文字列やmempcyのコピーが小さすぎるメモリなどを探します。通常、グローバル/スタック変数がランダムに上書きされる問題の原因です。

は新しい、
  • クリックデータブレークポイントをクリックして

    1. ゴーブレークポイントウィンドウ
    2. にVS2005でのウォッチポイント(broneの指示)を追加します。アドレスボックスに
    3. &gc_ppePlayerを入力し、 他の値だけを残します。
    4. 次に実行します。 gc_ppePlayer変更、 ブレークポイント がヒットします

    。 - brone

  • +0

    うーん、私はまさにそれを行うのですか?私はウォッチダイアログを持っていますが、それはあなたが意味するものだとは思いません。私はVisual Studio 2005を使用しています。 – Aistina

    +0

    私はVSでの経験はありませんが、その塩の価値があるデバッガはウォッチポイント(値の変更にトリガされるデータのエッセンシャル・ブレークポイント)を設定できる必要があります。あなたの次の質問は、VS2005でウォッチポイントを設定する方法です) – hhafez

    +0

    @hhafez - VS2005の値が変更されたときに検出することが可能であるかどうかはわかりませんでした。私はあなたがちょうど様々な主要な場所でブレークポイントを設定し、値が希望の値に変更されているかどうかを確認しなければならないと考えました(条件付きブレークポイントでこれを達成することもできます)。 – LeopardSkinPillBoxHat

    2

    私の最初の考えは、memDelete()が呼び出されたときにSpawnEntity()が "クリア"になっている内部メンバへのポインタを返すということです。ポインターが0xffffffffに設定されているのはわかりませんが、memDelete()の呼び出し中にポインターが発生した場合は、ASSERTが発生していない理由を説明します。つまり、0xffffffffはNULLと同じではありません。

    コードベース全体を再構築してからどれぐらいかかりましたか?私はこのようなメモリの問題を、ソリューション全体を単純に再構築するだけで解決できることを何度も見てきました。

    機能の最後にステップオーバー(F10)の代わりにステップ(F11)を実行しようとしましたか?あなたの例ではローカル変数は表示されませんが、簡単にするためにいくつか残しておいたのかもしれません。そうであれば、F11はそれらの変数のいずれかのためにデストラクタに入る(うまくいけば)ので、そのうちの1つが問題を引き起こしているかどうかを確認することができます。

    +0

    +1。これは最も可能性の高い説明のようです。 –

    +0

    この関数内の唯一の変数は戻り値の下にあるため、デストラクタは呼び出されません。とにかく、私が使用しているSDKのコメントは、CreateEntityがエンティティをそのプロパティ(エディターで内部的に使用する)に結びつけ、SpawnEntityは再生中にエンティティを作成するためのセパレーターであると言っています。 – Aistina

    +0

    memDelete()の呼び出しを一時的に削除するとどうなりますか?ポインタはそのままですか? –

    0

    "ファンダンゴオンコア"があります。

    動的初期化は、メモリのさまざまなビット(sic)を上書きします。

    直接的または間接的に、グローバルが上書きされています。 ヒープに相対的なメモリ内のグローバルはどこですか?

    バイナリは、問題がなくなるまで動的に初期化された部分を切り詰めます。 (再帰的に半角でコメントアウト)

    0

    あなたがいるプラットフォームによっては、この種のメモリ問題をすぐに理解できるツール(無料または有料)があります。私の頭の上オフ

    関連する問題