tags:

views:

104

answers:

5

Hello, everyone!

I have a game I'm working on. My players are stored in a vector, and, at the end of the game, the game crashes when trying to insert the high-scores in the correct positions.

Here's what I have (please ignore the portuguese comments, the code is pretty straightforward :P):

//TOTAL_HIGHSCORES is the max. number of hiscores that i'm willing to store. This is set as 10.
bool Game::updateHiScores()
{
    bool stopIterating;
    bool scoresChanged = false;
    //Se ainda nao existirem TOTAL_HISCORES melhores pontuacoes ou se a pontuacao for melhor que uma das existentes
    for (size_t i = 0; i < players.size(); ++i)
    {

    if (hiScores.empty())
        checkForValues = true;
    else
        checkForValues = (hiScores.size() < TOTAL_HISCORES || hiScores.back() < players[i].getScore());
    if (players[i].getScoreValue() > 0  && checkForValues)
        {
            scoresChanged = true;

            if(hiScores.empty() || hiScores.back() >= players[i].getScore())
                hiScores.push_back(players[i].getScore());
            else
            {   
                //Ciclo que encontra e insere a pontuacao no lugar desejado
                stopIterating = false;
                for(vector<Score>::iterator it = hiScores.begin(); it < hiScores.end() && !(stopIterating); ++it) 
                {
                    if(*it <= players[i].getScore())
                    {
                        //E inserida na posicao 'it' o Score correspondente
                        hiScores.insert(it, players[i].getScore());
                        //Verifica se o comprimento do vector esta dentro do desejado, se nao estiver, este e rectificado
                        if (hiScores.size() > TOTAL_HISCORES)
                            hiScores.pop_back();
                        stopIterating = true;
                    }
                }
            }
        }
    }

    if (scoresChanged)
        sort(hiScores.begin(), hiScores.end(), higher);

    return scoresChanged;
}

What am I doing wrong here?

Thanks for your time, fellas.

EDIT:

I ended up simplifying my code to this:

bool scoresChanged;

vector<Score> hiScoresCopy = hiScores;

for (size_t i = 0; i < TOTAL_PLAYERS; ++i)
    hiScoresCopy.push_back(players[i].getScore());

sort(hiScoresCopy.begin(), hiScoresCopy.end(), higher);

scoresChanged = (hiScores != hiScoresCopy);

if (scoresChanged)
{
    if (hiScoresCopy.size() > TOTAL_HISCORES)
        hiScoresCopy.resize(TOTAL_HISCORES);
    hiScores = hiScoresCopy;
}

return scoresChanged;
+2  A: 

A couple of things:

  • This code looks wrong:

    it < hiScores.end()
    

    because when using iterators and end() you should compare with "!=" instead of "<". You want to iterate until the LAST item, and "!= hiScores.end()" is the way to do that.

  • Do you have a debugger available? If so, run your code through it, then see where it dies - that's a fast way to figure out where it's failing.

svec
changed to it < hiScores.end(), but still crashes. I'll try debugging, but I'm pretty new at it.
Francisco P.
couldn't get VS2008 to debug, since i depend on txt files.
Francisco P.
@Francisco: What does depending on text files have to do with debugging?
James McNellis
I can't get them to load. Where should I place them?
Francisco P.
There's nothing inherently wrong with using `<` for random access iterators so long as both operands are valid and from the same container.
Charles Bailey
But it does hurt portability to another container.
Matthieu M.
I prefer != because it's the idiomatic way, I don't think it buys you anything to NOT use it by default, unless you're darn sure you don't need to. But as @Charles Bailey said, it's not technically required.
svec
+1  A: 

In your first if, you call hiScores.back() without checking if hiScores is empty.

rlbond
Good call, yet it still crashes. updated the code.
Francisco P.
+2  A: 

You don't say exactly where the code crashes or what the nature of the crash so I shall guess.

This test is the wrong way around.

it < hiScores.end() && !(stopIterating)

In one common case your iterator it will be invalidated in the same clause that you set stopIterating to true.

You could do this (!= is more idiomatic than < for iterators although both work for vectors).

!stopIterating && it != hiScores.end()

Alternatively, after your insertion you could just have break; statement and do away with the stopIterating variable. I think that this would be clearer for most readers of the code.

Charles Bailey
I don't say it because I can't find out, I am doing some cout detective word but I've had no luck. Thanks for your input!
Francisco P.
Holy crap, the ONLY thing I did was turn it into a break; and it stopped crashing. Why does this happen and how can I transfer all my rep to you?
Francisco P.
@Francisco P.: I don't know what sort of environment you are using but it might be that you have some checking iterators that were throwing an error because you were comparing an potentially invalidated iterator. I wouldn't expect a crash in an optimized build as your `stopIterating` variable would have stopped the loop quite quickly and usually just incrementing or comparing invalidated iterators into a vector doesn't cause a crash (even if it is undefined behaviour) unless the iterators have explicit checking code enabled.
Charles Bailey
+1  A: 

Is there any reason you can't simplify your code to the following?

bool Game::updateHiScores()
{
    for (size_t i = 0; i < players.size(); ++i)
    {
        hiScores.push_back(players[i].getScore());
    }
    sort(hiScores.begin(), hiScores.end(), higher);

    if (hiScores.size() > TOTAL_HIGHSCORES)
    {
        hiScores.erase(hiScores.begin() + TOTAL_HIGHSCORES, hiScores.end());
    }

    return true;
}
FredOverflow
That won't always return the correct value (and you might want to move the sort up a few lines).
Beta
@Beta Whoops, thanks.
FredOverflow
+1  A: 

I think Charles Bailey is right, but I also think that this code is unnecessarily complex. You could just do this:

bool Game::updateHiScores()
{
  if(players.empty())
    return(false);

  vector<Score> newScores;
  for(vector<Player>::iterator itr = players.begin() ; itr != players.end(); ++itr)
    newScores.push_back(itr->getScore());

  sort(newScores.begin(), newScores.end(), higher);

  if(hiScores.size() < TOTAL_HISCORES || newScores.front() > hiScores.back())
  {
    hiScores.insert(highScores.end(), newScores.begin(), newScores.end();
    sort(hiScores.begin(), hiScores.end(), higher);
    if(hiScores.size() > TOTAL_HISCORES)
      hiScores.resize(TOTAL_HISCORES);
    return(true);
  }
  return(false);
}
Beta
Before you answered I devised another solution, but thanks for your input!
Francisco P.