Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mysterious heisenbug?

Tags:

c++

pdcurses

So I'm making a snake game with teleports and the usual mice. I had a loop running like this:

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

The problem with the above code was that displayInfo gets called before the score gets updated, and so after eating a mouse, the user has to wait until the loop runs again to see his score updated. So I moved that one line of code to the bottom of the function:

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

and teleports stop working! The program crashes whenever the snake reaches a teleport. And displayInfo uses the following code:

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

Where printLine only has a color_set, mvprintw, and refresh(). Nothing to do with Teleports. Weird.

So I went to the snake function where the snake gets its next location from a teleport:

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

Where teleports[overlap(next)]->teleportFrom(dir) returns the location the snake is to be teleported to. In an attempt to see why it was crashing (perhaps Teleport was returning some location offscreen?), I added the following 3 lines before the above line:

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

And the problem disappears!

Not only that, but I HAVE to have those three lines. If I comment out mvprintw(1, 0, "(%i, %i)", l.x, l.y);, or refresh();, or both, the program crashes as before upon reaching a teleport.

Any ideas on what might be causing this behavior?

UPDATE: I tried removing all warnings (which were mostly warnings about comparisons of signed/unsigned numbers), but only 1 remains so far:

warning: reference to local variable 'other' returned

And the code:

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

What do I do to fix this warning?

like image 907
wrongusername Avatar asked Sep 12 '10 23:09

wrongusername


1 Answers

Build your assignment operator like this:
You should always return *this (even if they were equal). But they never would since you were creating a local copy (so this was not your error).

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

The standard copy and swap seemed a bit overkill for such a simple class.

PS. You should fix all warnings (even if they are as simple as the unsigned mismatch). If you do not fix them you will become immune to their potency and will not spot a real problem because it is surrounded by warning that you are ignoring. So fix them all (aI always turn on the flag that makes the compiler treat all warnings as errors so that the code does not compile if there are any warnings).

The correct way to implement assignment operator (or the most commonly accepted good way). Is to use the copy and swap idiom:

// 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);
}
like image 50
Martin York Avatar answered Sep 21 '22 17:09

Martin York