Domanda

Sto lavorando a un gioco e attualmente sto lavorando alla parte che gestisce l'input. Qui sono coinvolte tre classi, c'è la classe ProjectInstance che inizia il livello e roba del genere, c'è un GameController che gestirà l'input e un PlayerEntity che sarà influenzato dai controlli determinati da GameController . All'avvio del livello, ProjectInstance crea il GameController e chiamerà il suo metodo EvaluateControls nel metodo Step, che viene chiamato all'interno del loop di gioco. Il metodo EvaluateControls è un po 'simile a questo:

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
}

Questa funzione è chiamata correttamente e l'asserzione non si innesca mai. Tuttavia, ogni volta che questa funzione viene chiamata, gc_ppePlayer è impostato su NULL. Come puoi vedere non è una variabile locale che esca dall'ambito. L'unico posto in cui gc_ppePlayer può essere impostato su NULL è nel costruttore o possibilmente nel distruttore, nessuno dei quali viene chiamato tra le chiamate a EvaluateControls . Durante il debug, gc_ppePlayer riceve un valore corretto e previsto prima del reso. Quando premo F10 ancora una volta e il cursore si trova sulla parentesi graffa di chiusura, il valore cambia in 0xffffffff. Sono in perdita qui, come può succedere? Chiunque?

È stato utile?

Soluzione

Stai eseguendo il debug di una configurazione di rilascio o debug? Nella configurazione della build di rilascio, ciò che vedi nel debugger non è sempre vero. Vengono effettuate ottimizzazioni e questo può far sì che la finestra dell'orologio mostri valori bizzarri come quelli che stai vedendo.

Stai effettivamente vedendo il trigger ASSERT? Gli ASSERT vengono normalmente compilati dalle build di rilascio, quindi suppongo che tu stia eseguendo il debug di una build di rilascio, motivo per cui ASSERT non sta causando la chiusura dell'applicazione.

Vorrei raccomandare di creare una versione di debug del software, e quindi vedere se gc_ppePlayer è davvero NULL. Se lo è davvero, forse stai vedendo un danneggiamento dell'heap di memoria di qualche tipo in cui questo puntatore viene sovrascritto. Ma se fosse una corruzione della memoria, sarebbe generalmente molto meno deterministico di quanto tu stia descrivendo.

A parte questo, l'utilizzo di valori di puntatore globali come questo è generalmente considerato una cattiva pratica. Verifica se puoi sostituirlo con una classe singleton se è veramente un singolo oggetto e deve essere accessibile a livello globale.

Altri suggerimenti

imposta un punto di controllo su gc_ppePlayer == NULL quando il valore di quell'espressione cambia (in NULL o da NULL) il debugger ti indicherà esattamente dove è successo.

Provalo e guarda cosa succede. Cerca stringhe non terminate o copia mempcy in memoria troppo piccola, ecc ... di solito è la causa del problema delle variabili globali / stack che vengono sovrascritte in modo casuale.

Per aggiungere un watchpoint in VS2005 (istruzioni di brone)

  
      
  1. Vai alla finestra Punti di interruzione
  2.   
  3. Fai clic su Nuovo,
  4.   
  5. Fai clic su Punto di interruzione dati. Invio
  6.   
  7. & amp; gc_ppePlayer nella casella Indirizzo, lascia   solo altri valori.
  8.   
  9. Quindi esegui.
  10.   
     

Quando gc_ppePlayer cambia,   punto di rottura       sarà colpito. - brone

Il mio primo pensiero è quello di dire che SpawnEntity () sta restituendo un puntatore a un membro interno che sta per essere "cancellato". quando viene chiamato memDelete (). Non mi è chiaro quando il puntatore è impostato su 0xffffffff, ma se si verifica durante la chiamata a memDelete (), questo spiega perché il tuo ASSERT non si attiva - 0xffffffff non è lo stesso di NULL.

Quanto tempo è passato da quando hai ricostruito l'intera base di codice? Ho visto problemi di memoria come questo ogni tanto che vengono risolti semplicemente ricostruendo l'intera soluzione.

Hai provato a fare un passo in (F11) invece del passaggio (F10) alla fine della funzione? Sebbene il tuo esempio non mostri alcuna variabile locale, forse ne hai lasciato fuori qualcuno per semplicità. In tal caso, F11 entrerà (si spera) nei distruttori di una di quelle variabili, permettendoti di vedere se una di esse sta causando il problema.

Hai un " fandango sul core. "

L'inizializzazione dinamica sta sovrascrivendo bit assortiti (sic) di memoria.

O direttamente o indirettamente, il globale viene sovrascritto. dov'è il globale in memoria rispetto all'heap?

binario taglia la porzione inizializzata dinamicamente fino a quando il problema non scompare. (commenta metà alla volta, in modo ricorsivo)

A seconda della piattaforma su cui ci si trova ci sono strumenti (gratuiti o a pagamento) che possono capire rapidamente questo tipo di problema di memoria.

In cima alla mia testa:

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top