Domanda

Così sto facendo un gioco del serpente con teletrasporti e il solito topi. Ho avuto un ciclo in esecuzione in questo modo:

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

Il problema con il codice di cui sopra è che displayInfo viene chiamato prima che il punteggio viene aggiornato, e così dopo aver mangiato un topo, l'utente deve attendere che il ciclo viene eseguito di nuovo per vedere il suo punteggio aggiornato. Così ho spostato che una riga di codice nella parte inferiore della funzione:

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

e teleporti smettere di lavorare! Il programma si blocca ogni volta che il serpente raggiunge un teletrasporto. E displayInfo utilizza il seguente codice:

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);

Dove printLine ha solo color_set, mvprintw e refresh(). Niente a che vedere con Teleports. Strano.

Così sono andato alla funzione serpente in cui il serpente prende il prossimo luogo da un teletrasporto:

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

Dove teleports[overlap(next)]->teleportFrom(dir) restituisce la posizione del serpente deve essere teletrasportato a. Nel tentativo di capire perché si è in crash (? Forse Teleport stava tornando una certa posizione fuori campo), ho aggiunto le seguenti 3 righe prima della riga sopra:

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

E il problema scompare!

Non solo, ma devo avere quelle tre righe. Se io commento mvprintw(1, 0, "(%i, %i)", l.x, l.y);, o refresh();, o di entrambi, il programma si blocca come prima al raggiungimento di un teletrasporto.

Tutte le idee su che cosa potrebbe causare questo comportamento?

UPDATE: Ho provato a rimuovere tutti gli avvisi (che erano per lo più gli avvertimenti circa il confronto di numeri firmato / unsigned), ma solo 1 rimane finora:

warning: reference to local variable 'other' returned

E il codice:

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

Che cosa posso fare per risolvere questo avviso?

È stato utile?

Soluzione

Crea il tuo operatore di assegnazione in questo modo:
Si dovrebbe sempre tornare * questo (anche se erano uguali). Ma non hanno mai avrebbero dato che stavano creando una copia in locale (quindi non è stato l'errore).

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

La copia standard e scambiare sembrava un po 'eccessivo per una classe così semplice.

PS. Si dovrebbe risolvere tutte le avvertenze (anche se sono così semplici come la mancata corrispondenza non firmato). Se non li risolvere si diventa immuni alla loro potenza e non sarà posto un problema reale, perché è circondato da avvertendo che si sta ignorando. Quindi, tutti risolvere (AI accendere sempre la bandiera che rende il trattamento compilatore tutti gli avvisi come errori in modo che il codice non viene compilato se ci sono eventuali avvisi).

Il modo corretto per implementare operatore di assegnazione (o il modo buono più comunemente accettata). È quello di utilizzare la copia e di swap linguaggio:

// 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);
}

Altri suggerimenti

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

Questo restituisce un riferimento. Quando la funzione ritorna, cosa succede a other? (Muore, e si sta facendo riferimento a nulla.) Dal momento che questa è la classe hai a che fare con intorno alla zona problema, questa è probabilmente la causa. Ri-organizzare circonda foglie di codice lo stack in una certa condizione in cui si riferisce alla variabile morti "opere".

Cambia a return *this, o semplicemente rimuovere il controllo di tutto. (Assegnazione di due variabili, senza un ramo sarà probabilmente sempre correre più veloce che l'aggiunta di un ramo, su una CPU moderna.)

(Si dovrebbe anche prendere in generale il parametro per riferimento, invece che per valore.)

Hai controllato il codice che sta causando questa anomalia? Il heisenbug fenomeni citato qui:

  

Un esempio comune è un errore che si verifica in un programma che è stato compilato con un compilatore ottimizzato, ma non nello stesso programma quando viene compilato senza ottimizzazione (ad esempio, per generare una versione di debug-mode)

Ecco alcune linee guida:

  • condizione Race? stai usando le discussioni?
  • Pointer trabocco qualche confine?
  • eseguire il codice attraverso valgrind per monitorare eventuali cambiamenti insoliti / irregolare in buffer di memoria da qualche parte

Un'altra citazione:

  

Un motivo comune per heisenbug simile comportamento è che l'esecuzione di un programma in modalità debug spesso pulisce memoria prima dell'inizio del programma, e variabili forze sulle posizioni dello stack, invece di tenerli in registri. Queste differenze di esecuzione possono alterare l'effetto di insetti che richieda l'accesso fuori dal campo membro o ipotesi non corretti per il contenuto iniziale di memoria. Un'altra ragione è che debuggers comunemente prevedono orologi o altre interfacce utente che causano ulteriore codice (ad esempio accesso alle proprietà) da eseguire, che può, a sua volta, cambiare lo stato del programma. Ancora un altro motivo è un fandango sul nucleo, l'effetto di un puntatore correre fuori limite. In C ++, molti heisenbug sono causati da variabili non inizializzate.

Assicurarsi che gli interruttori sono spenti - nessuna ottimizzazione, informazioni complete di debug, deselezionare costruisce ogni esistente, riavviare l'IDE e ricompilazione di nuovo ....

Prima di tutto, la posizione :: operator = dovrebbe essere come questo, invece:

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

Tuttavia, che, probabilmente, non spiega l'incidente. Bad puntatori sullo stack qui non si arrestano sulla maggior parte delle architetture (supponendo che x ed y sono int).

Ora, questo è un mandelbug, non un heisenbug. Hai qualcun altro di memoria da qualche parte corrompere. Buona fortuna.

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