"Vector erase iterator out range"

Apr 29, 2013 at 9:40pm
This is the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
for(int i = 0; i < zombies.size(); i++)
	{
		zombies[i]->Move();
		for(int x = 0; x < player.ReturnVector().size(); x++)
		{
			if(zombies[i]->RS().getGlobalBounds().contains(player.ReturnVector()[x].RS().getPosition()))
			{
				zombies.erase(zombies.begin() + i); //works perfectly
				player.ReturnVector().erase(player.ReturnVector().begin() + x); //line that gives error
			}
		}

	}


I don't understand why it's happening because the line above it has the exact same values passing though it and it works.

When I used debug, I found that after I shoot a bullet, X (from the for loop) is equal to 0 and player.vector has a value of 1. Which is expected.
Last edited on Apr 29, 2013 at 9:41pm
Apr 29, 2013 at 9:48pm
What are the types of zombies and player.ReturnVector()?
Apr 29, 2013 at 9:50pm
zombies: std::vector<Zombie*> zombies; (Zombie is a class)

player's vector: std::vector<Bullet> bullets; (Bullet is a class)
player's function:
1
2
3
4
std::vector<Bullet> Player::ReturnVector()
{
	return bullets;
}


Sorry for not adding this to start with.
Last edited on Apr 29, 2013 at 9:53pm
Apr 29, 2013 at 9:57pm
Good. Guess why on line 9 the player.ReturnVector().begin() does not refer to the same memory as the vector that you try to erase from.

Hint: function returns a copy.
Apr 29, 2013 at 10:01pm
But wouldn't every time the if statement is called it'd return a fresh copy of the vector?
Apr 29, 2013 at 10:09pm
Every time you call ReturnVector(), you get a new copy. You never touch the vector that is inside player ...
Apr 29, 2013 at 10:16pm
OH! I understand now.

What would be the best way to change the vector from the function rather than just returning it?
Apr 29, 2013 at 10:37pm
1
2
3
4
std::vector<Bullet>& Player::ReturnVector()
{
    return bullets ;
}


However, that won't be the end of your problems. I wouldn't suggest using for loops here.

Whenever you delete an element from a vector, the vector gets smaller. What happens in the inner for loop when the vector's size becomes equal to i? What's more, when you erase an element every element is moved down one index. (When you erase vector[7], vector[8] becomes vector[7].) So you end up not checking some elements against other elements.

I would expect your code to look more like the following (disclaimer: Not tested, may require some minor adjustments to work correctly.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    auto zombie = zombies.begin() ;
    while ( zombie != zombies.end() )
    {
        (*zombie)->Move() ;

        auto & bulletVec = player.ReturnVector() ;
        auto bullet = bulletVec.begin() ;

        while ( bullet != bulletVec.end() && !((*zombie)->RS().getGlobalBounds().contains(bullet->RS().getPosition())) )
            ++bullet ;

        if ( bullet != bulletVec.end() )
        {
            zombie = zombies.erase(zombie) ;
            bulletVec.erase(bullet) ;
        }
        else
            ++zombie ;
    }


Also, I think the design would benefit from the bullets vector being divorced from the player object.
Last edited on Apr 29, 2013 at 10:40pm
Apr 29, 2013 at 10:56pm
Oh wow, there's so much I don't know. Ha.

Thanks a lot. I'll definitely experiment with that! (the reference worked).

I just go into messing with iterators (you're using iterators right there, right?)
Apr 30, 2013 at 2:00am
you're using iterators right there, right?


Correct.
Topic archived. No new replies allowed.