sandmaster
sandmaster

Reputation: 65

C++ Access Violation Reading location 0x003AE000 when trying to erase from vector

I am getting an error when I try to erase an item from an vector if the item is set to not alive by a boolean. I have tried searching the net but havn't found anything about it. I have tried to find different ways to delete elements on index x in a vector and found the function: vector.erase(vector.begin() + index)

So when I try using it in my for loop I get access violation reading location pointing at the erase function line.

Code for the loop where the error is:

    if (!player.getBullets().empty())
    {
        for (int x = 0; x < player.getBullets().size(); x++)
        {
            //Check for projectiles whos status is dead.
            if (!player.getBullets()[x]->getAlive())
            {
                //Erase the element at position x.
                player.getBullets().erase(player.getBullets().begin() + x);

            }
        }
    }

Upvotes: 0

Views: 1484

Answers (3)

Vlad from Moscow
Vlad from Moscow

Reputation: 310910

Though the loop is invalid because counter x is increased while the size of the vector is decreased and as the result not all the vector is traversed I do not see the reason of the access violation. I think that the problem is related to objects stored in the vector.

Upvotes: 0

James M
James M

Reputation: 16718

It's much easier to erase correctly if you use an iterator instead of an index. An (almost) direct conversion of your code:

vector<Projectile*> bullets = player.getBullets();

for (vector<Projectile*>::iterator x = bullets.begin(); x != bullets.end(); )
{
    //Check for projectiles whos status is dead.
    if (!(*x)->getAlive())
    {
        //Erase the element at position x.
        x = bullets.erase(x);
    }
    else
    {
        ++ x;
    }
}

Note that this only works with a local copy of the vector. If you want to update the vector in the player class itself, you will need to change getBullets to return a reference:

vector<Projectile*> &Sprite::getBullets()
{
    return bullets;
}

And then for the loop:

vector<Projectile*> &bullets = player.getBullets();

Upvotes: 0

Kerrek SB
Kerrek SB

Reputation: 476910

Don't reinvent the wheel, especially not the really difficult one that can go under water and up walls. Use a ready-made one:

#include <algorithm>

player.getBullets().erase(
    std::remove_if(player.getBullets().begin(),
                   player.getBullets().end(),
                   [](Projectile * p) -> bool { return !p->getAlive(); }),
    player.getBullets().end());

(I'm assuming that Bullet is the same as decltype(player.getBullets())::value_type, i.e. the element type of the bullets container. Adjust to suit.)

Upvotes: 2

Related Questions