Question

Je fais un jeu de serpent avec téléports et les souris habituelles. J'ai eu une boucle en cours d'exécution comme ceci:

while(snake.alive() && miceEaten < micePerLevel)
{
    displayInfo(lives, score, level, micePerLevel - miceEaten);
    //some code
    if(miceEaten())
    {
        //update score...
    }
    //more stuff...
}

Le problème avec le code ci-dessus est que displayInfo est appelé avant le score est mis à jour, et ainsi après avoir mangé une souris, l'utilisateur doit attendre jusqu'à ce que la boucle se présente à nouveau pour voir son score mis à jour. Donc, je me suis déplacé qu'une ligne de code au bas de la fonction:

while(snake.alive() && miceEaten < micePerLevel)
{
    //some code
    if(miceEaten())
    {
        //update score...
    }
    //more stuff...
    displayInfo(lives, score, level, micePerLevel - miceEaten);
}

et téléports cessent de fonctionner! Le programme se bloque chaque fois que le serpent atteint un téléport. Et displayInfo utilise le code suivant:

stringstream s;
s << "LEVEL " << left << setw(12) << level << "LIVES: " << setw(12) << lives << "MICE LEFT: " << setw(12) << miceLeft
    << "SCORE: " << setw(13) << score;
printLine(0, s.str(), WHITEONBLUE);

printLine a seulement color_set, mvprintw et refresh(). Rien à voir avec téléports. Bizarre.

Alors je suis allé à la fonction de serpent où le serpent tire son prochain emplacement d'un téléport:

    body.push_back(teleports[overlap(next)]->teleportFrom(dir)); //next is a Location object

teleports[overlap(next)]->teleportFrom(dir) retourne l'emplacement du serpent doit être téléporté. Pour tenter de comprendre pourquoi il plantait (? Peut-être Teleport retournait un emplacement hors champ), j'ai ajouté les 3 lignes suivantes avant la ligne ci-dessus:

    Location l = teleports[overlap(next)]->teleportFrom(dir);
    mvprintw(1, 0, "(%i, %i)", l.x, l.y);
    refresh();

Et le problème disparait!

Non seulement cela, mais je dois d'avoir ces trois lignes. Si je commente sur mvprintw(1, 0, "(%i, %i)", l.x, l.y);, ou refresh();, ou les deux, le programme se bloque comme avant après avoir atteint un téléport.

Toutes les idées sur ce qui pourrait être la cause de ce comportement?

Mise à jour: J'ai essayé de supprimer tous les avertissements (qui étaient pour la plupart des avertissements sur les comparaisons de chiffres signés / non signés), mais seulement 1 reste jusqu'à présent:

warning: reference to local variable 'other' returned

Et le code:

Location& Location::operator = (Location other)
{
    if(this == &other)
        return other;
    x = other.x;
    y = other.y;
    return *this;
}

Que dois-je faire pour corriger cet avertissement?

Était-ce utile?

La solution

Construisez votre opérateur d'affectation comme ceci:
Vous devez toujours retourner * ce (même si elles étaient égales). Mais jamais ils ne vous créez depuis une copie locale (donc ce n'était pas votre erreur).

Location& Location::operator = (Location const& other)
{
    // Does it really matter if you assign to self?
    x = other.x;
    y = other.y;
    return *this;
}

La copie standard et d'échange semblait un peu exagéré pour une telle classe simple.

PS. Vous devez fixer tous les avertissements (même si elles sont aussi simples que le décalage non signé). Si vous ne fixez-les vous deviendrez à l'abri de leur puissance et ne sera pas repérer un vrai problème, car il est entouré d'avertissement que vous ignorez. Alors les fixer tous (aI toujours allumer le drapeau qui rend le traitement du compilateur tous les avertissements comme des erreurs afin que le code ne compile pas s'il y a des avertissements).

La bonne façon de mettre en œuvre l'opérateur d'affectation (ou la bonne façon la plus communément admise). Est d'utiliser l'idiome de copie et d'échange:

// notice the parameter is passed by value (i.e. a copy).
// So the copy part is aromatically taken care of here.
// So now you just need tom implement the swap() part of the idiom.
Location& Location::operator = (Location other)
{
    this->swap(other);
    return *this;
}

void Location::swap(Location& other)
{
    std::swap(x, other.x);
    std::swap(y, other.y);
}

Autres conseils

Location& Location::operator = (Location other)
{
    if(this == &other)
        return other;
    x = other.x;
    y = other.y;
    return *this;
}

renvoie une référence. Lorsque la fonction retourne, ce qui se passe à other? (Il meurt, et vous parlez de rien.) Étant donné que c'est la classe que vous avez affaire à la zone de problème, ce qui est probablement la cause. Réorganisant autour des feuilles de code de la pile dans un certain état où se référant à la variable morte « œuvres ».

Modifier à return *this, ou tout simplement retirer le chèque tout à fait. (Affectation deux variables sans une branche se déroulera probablement toujours plus vite que l'ajout d'une branche, sur une unité centrale de traitement moderne.)

(Vous devez prendre aussi généralement le paramètre par référence, au lieu de par valeur.)

Avez-vous vérifié votre code qui est à l'origine de cette anomalie? Le phénomène Heisenbug cité ici:

  

Un exemple courant est un bug qui se produit dans un programme qui a été compilé avec un compilateur optimisé, mais pas dans le même programme lors de la compilation sans optimisation (par exemple, pour générer une version debug-mode)

Voici quelques directives:

  • condition de course? vous utilisez des fils?
  • quelque part limite de pointeur?
  • Exécuter votre code par valgrind pour surveiller tout changement inhabituel / irrégulier dans les tampons de mémoire quelque part

Une autre citation:

  

Une raison courante de comportement comme Heisenbug est que l'exécution d'un programme en mode débogage nettoie souvent la mémoire avant le début du programme, et les variables des forces sur des emplacements de la pile, au lieu de les garder dans les registres. Ces différences dans l'exécution peuvent modifier l'effet de bugs impliquant membre hors des limites d'accès ou des hypothèses erronées sur le contenu initial de la mémoire. Une autre raison est que les débogueurs fournissent généralement des montres ou d'autres interfaces utilisateur qui provoquent un code supplémentaire (comme accesseurs de propriété) à exécuter, qui peut, à son tour, changer l'état du programme. Une autre raison est un fandango sur le noyau, l'effet d'un pointeur en cours d'exécution hors limites. En C ++, beaucoup sont causées par bug logiciel inhabituel des variables non initialisées.

Assurez-vous que les interrupteurs sont éteints - aucune optimisation, complète les informations de débogage, de supprimer tous les builds existant, redémarrez l'IDE et encore recompilation ....

Tout d'abord, votre emplacement :: operator = devrait être comme ceci:

Location& Location::operator = (const Location &other)
{
    if(this == &other)
        return *this;
    x = other.x;
    y = other.y;
    return *this;
}

Cependant, cela ne probablement pas expliquer l'accident. Bad pointeurs sur pile ici ne plantent pas sur la plupart des architectures (en supposant x et y sont int).

Maintenant, c'est un mandelbug, pas Heisenbug. Vous avez quelqu'un d'autre mémoire corruptrice de quelque part. Bonne chance.

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