Question

Je travaille sur un jeu et je travaille actuellement sur la partie qui gère les entrées. Trois classes sont impliquées ici: il y a la classe ProjectInstance qui commence le niveau et le reste, il y a un GameController qui gérera l'entrée et un PlayerEntity qui sera influencé par les contrôles déterminés par GameController . Au démarrage du niveau, ProjectInstance crée le GameController et appelle sa méthode EvaluateControls dans la méthode Step, qui est appelée à l'intérieur de la boucle de jeu. La méthode EvaluateControls ressemble un peu à ceci:

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
}

Cette fonction est appelée correctement et l'assert ne se déclenche jamais. Cependant, chaque fois que cette fonction est appelée, gc_ppePlayer est défini sur NULL. Comme vous pouvez le constater, ce n'est pas une variable locale qui sort de la portée. Le seul endroit gc_ppePlayer pouvant être défini sur NULL est dans le constructeur ou éventuellement dans le destructeur, aucun des deux n'étant appelé entre les appels à EvaluateControls . Lors du débogage, gc_ppePlayer reçoit une valeur correcte et attendue avant le retour. Lorsque j'appuie sur F10 une fois de plus et que le curseur est sur l'accolade fermante, la valeur devient 0xffffffff. Je suis perdu ici, comment cela peut-il arriver? Quelqu'un?

Était-ce utile?

La solution

Déboguez-vous une configuration Release ou Debug? Dans la configuration de la version finale, ce que vous voyez dans le débogueur n'est pas toujours vrai. Des optimisations sont apportées. La fenêtre de surveillance peut ainsi afficher des valeurs bizarres, comme vous le voyez.

Voyez-vous réellement le déclenchement de l’ASSERT? Les ASSERT sont normalement compilés à partir de versions Release, alors je suppose que vous êtes en train de déboguer une version Release. C’est pourquoi ASSERT ne provoque pas la fermeture de l’application.

Je recommanderais de créer une version Debug du logiciel, puis de vérifier si gc_ppePlayer est vraiment NULL. Si c'est vraiment le cas, vous constatez peut-être une corruption de mémoire dans laquelle le pointeur est remplacé. Mais si c’était une corruption de mémoire, ce serait généralement beaucoup moins déterministe que ce que vous décrivez.

En passant, l’utilisation de valeurs de pointeur globales comme celle-ci est généralement considérée comme une mauvaise pratique. Voyez si vous pouvez remplacer ceci par une classe singleton s’il s’agit vraiment d’un objet unique et doit être accessible de manière globale.

Autres conseils

Définissez un point d'observation sur gc_ppePlayer == NULL lorsque la valeur de cette expression change (en NULL ou à partir de NULL), le débogueur vous indiquera exactement où il s'est passé.

Essayez cela et voyez ce qui se passe. Recherchez des chaînes non terminées ou des copies mempcy en mémoire trop petites, etc., ce qui est généralement la cause du problème de l'écrasement aléatoire des variables de pile / globales.

Pour ajouter un point de contrôle dans VS2005 (instructions détaillées)

  
      
  1. Accéder à la fenêtre Points d'arrêt
  2.   
  3. Cliquez sur Nouveau,
  4.   
  5. Cliquez sur le point d'arrêt de données. Entrez
  6.   
  7. & amp; gc_ppePlayer dans la zone Adresse, laissez   autres valeurs seules.
  8.   
  9. Puis courez.
  10.   
     

Lorsque gc_ppePlayer change,   point d'arrêt       sera touché. - brone

Ma première pensée est de dire que SpawnEntity () renvoie un pointeur sur un membre interne qui est "effacé". quand memDelete () est appelé. Ce n'est pas clair pour moi quand le pointeur est réglé sur 0xffffffff, mais s'il se produit pendant l'appel à memDelete (), cela explique pourquoi votre ASSERT ne se déclenche pas - 0xffffffff n'est pas identique à NULL.

Depuis combien de temps avez-vous reconstruit la base de code entière? J'ai vu de temps en temps des problèmes de mémoire comme celui-ci, qui sont résolus en reconstruisant simplement la solution complète.

Avez-vous essayé de faire un pas dans (F11) au lieu du pas (F10) à la fin de la fonction? Bien que votre exemple ne présente aucune variable locale, vous en avez peut-être oublié pour des raisons de simplicité. Si tel est le cas, F11 entrera (espérons-le) dans les destructeurs de l'une de ces variables, vous permettant de voir si l'un d'entre eux est à l'origine du problème.

Vous avez un "fandango sur le noyau".

L’initialisation dynamique écrase divers bits de mémoire.

Que ce soit directement ou indirectement, le fichier global est écrasé. où est le global en mémoire par rapport au tas?

binaire coupe la partie initialisée dynamiquement jusqu'à ce que le problème disparaisse. (commentez récursivement, moitié à la fois)

Selon la plate-forme sur laquelle vous vous trouvez, il existe des outils (gratuits ou payants) qui peuvent rapidement résoudre ce type de problème de mémoire.

De mémoire:

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top