views:

911

answers:

2

Hi, I'm having a problem with my looping over a vector, and deleting values from another vector sometimes crashes my program. I have this vector of int's to keep track of which elements should be removed.

std::vector<int> trEn;

Then I loop through this vector:

struct enemyStruct {
    float x, y, health, mhealth, speed, turnspeed;
    double angle, tangle;
};
std::vector<enemyStruct> enemies;

The loop looks like this:

for ( unsigned int i = 0; i < bullets.size(); i++ ) {
 for ( unsigned int j = 0; j < enemies.size(); j++ ) {
  if ( bullets[i].x > enemies[j].x-10 && bullets[i].x < enemies[j].x+10 && bullets[i].y > enemies[j].y-10 && bullets[i].y < enemies[j].y+10 )
  {
   enemies[j].health-=bullets[i].dmg;
   if(enemies[j].health<=0){trEn.push_back(j);break;}
  }
 }
}

The bullets vector is just another vector similar to the enemies vector, but with bullets in it. That one does not seem to be the problem. All this code works well, but when it comes to actually delete the items in my enemies vector the program sometimes crashes.

std::reverse( trEn.begin(), trEn.end() );
for ( unsigned int g = 0; g < trEn.size(); g++ ) {
 unsigned int atmp = trEn.at(g);
 if(atmp<=enemies.size()&&atmp>=0)enemies.erase(enemies.begin()+atmp,enemies.begin()+atmp+1);
} trEn.clear();

First I reverse the vector of int´s so that it will go from back to front. If i did´nt do this all values after trEn[0] would be invalid. This is the loop which gives me a crash, but only sometimes. What I´m trying to do is a top-down shooter game, and it seems that when lots of things should be removed at the same time it just crashes. Please help me with this!

Just ask if I was unclear or if there is anything missing.

+4  A: 

The only seemingly obvious thing would be:

if(atmp<=enemies.size() ...

Are you sure you do not mean (atmp < enemies.size()) here? Otherwise your code

enemies.erase(enemies.begin()+atmp, ...

will for sure produce some serious issues.

gimpf
Yay it worked, thanks!I thought that that would make it skip if it was the last vector record, but instead I was trying to remove something out of the vector size.Now I can run around spraying zombies with my sawn´off shotgun, making their limbs fly all over the place!
Mariamario
Actually - that should probably be an assertion rather than a conditional as from what I can tell it should never be possible for atmp to be >= than the size of enimies.
Richard Corden
Depends too much on the rest of the code, which is not shown. But for the context of this question I agree that the OP probably had that in mind.
gimpf
You're probably right that it should'nt be possible for it to be that way. That check was just needed before I was reversing the vector not as a thing that should make it not crash rather than to make it work correctly. Sorry I have to ask, but what does it mean that it should be an assertion? :o
Mariamario
Am I right if I think that assertion means the program should catch it as an error if atmp > size of enemies as that shouldn't be possible? I'm such a newbie sometimes...
Mariamario
What I mean here by assertion is that, in using an if statement there is an implicit expectation that the condition of the "if" may be false sometimes. However, it seems to me that it should never be. If the resulting code requires the "if", then it's simply hiding a flaw. I would change this to "assert (! atmp >= enimies.size())" or maybe use an "if" but throw an exception if dying immediately is not an option: "if (atmp => enimies.size ()) throw SeriousErrorInCode ();".
Richard Corden
Ah, thanks for the explanation. Will change that. But if I just skipped the whole check which now is'nt needed as I see it, it would probably be faster. But would that be bad coding?
Mariamario
This is its own can of worms! Personally, I'm a believer of using the standard 'assert' macro. In release builds I then use "-D NDEBUG" which results in the code in the assert being removed. The idea is that in debug builds you have the assertions (to help you develop your program and check your assumptions) and then because you've got an excellent and compreshensive test suite you can disable the assertions in the release build, since you've confirmed that your code is perfect! ;)
Richard Corden
BTW, other people have different opinions on assert - checkout http://stackoverflow.com/questions/117171/design-by-contract-tests-by-assert-or-by-exception/119795#119795
Richard Corden
Thanks, that's very useful to me!To me I think assertion is the right thing to do as I do not wish to compromize in speed, but still want to debug my game so I don't get any unwanted results/crashes.
Mariamario
Well, performance considerations should not be the primary incentive here. It's really all about invariants vs. exceptional situations. Invariants simply must not be broken, or the programming is incorrect. Exception situations may arise, and therefore must be checked during runtime. Invariants do not need to be checked (in correct code they simply are never broken), but depending on some other factors you might want to. Performance usually is not the problem, especially not on this level of programming. Confusion perfected?
gimpf
+2  A: 

Your first code sample are two nested loops - you iterate over bullets and for each bullet you iterate over enemies adding enemy indices to trEn vector. What makes you think that contents of trEn are sorted in ascending order after that? For first bullet you can add index 3, and for the second index 2. You can even add same index for different bullets. Or am I missing something?

Tadeusz Kopec
Ah, that´s a good point, didn´t think of that. In fact I just realized that enemies in the middle of the enemy horde could disappear as I was shooting at the ones at the front, which means the ordering is messed up anyway. Since it´s a vector of integers it should be easy to sort though. Is there some standard function to do the sorting or should I make my own?
Mariamario
I guess std::sort will do :-)
Tadeusz Kopec
Thanks, it works great now :)
Mariamario
It seems that it still removes more than one enemy sometimes and it's pretty obvious it's because of duplicate entries in the vector. Is there some magical function to remove those also?
Mariamario
You might want to use std::set. It is sorted, and it's elements are unique.
gimpf