Ben Humphries
Ben Humphries

Reputation: 60

C++ Access Violation when executing pointer

I'm working on a game with c++ and sfml where I have asteroids falling down the screen and the player shoots lasers up to destroy them. When the asteroids or lasers go off of the screen, they are deleted and erased from their respective std::vectors:

asteroids:

std::vector<Asteroid*>::iterator it;
for (it = asteroids.begin(); it < asteroids.end(); ) {
    (*it)->update(dt);

    if ((*it)->getPosition().y > Game::window.getSize().y) {
        delete * it;
        asteroids.erase(it);
    }
    else {
        it++;
    }
}

lasers:

for (int i = 0; i < lasers.size(); i++) {
    lasers.at(i)->update(dt);

    if (lasers.at(i)->getPosition().y < 0) {
        delete lasers.at(i);
        lasers.erase(lasers.begin() + i);
        i--;
    }
}

The issue comes when I try to detect collisions between them. I loop through all of the asteroids in each instance of laser, and check the collisions between them using a method from a parent class, GameObject.

for (int i = 0; i < Game::spawner->asteroids.size() - 1; i++) {

    if (isColliding(asteroids.at(0))) { // Access violation executing location 0x071DE528.
        printf("collided");
        //delete asteroids.at(i);
        //asteroids.erase(asteroids.begin() + i);
        break;
    }
}

Here is the isColliding and getPosition method:

bool GameObject::isColliding(GameObject * g) {

sf::Vector2f gPos = g->getPosition();
sf::Vector2f pos = this->getPosition(); // after waiting a few seconds and then testing the collision, I get this error here: Access violation executing location 0x00000000.



if (gPos.x <= pos.x && pos.x <= gPos.x + g->width 
    || pos.x <= gPos.x && gPos.x <= pos.x + width) {

    if (gPos.y <= pos.y && pos.y <= gPos.y + g->height
        || pos.y <= gPos.y && gPos.y <= pos.y + height) {

        return true;
    }
}
return false;

}

sf::Vector2f GameObject::getPosition() {

if (isLoaded) {
    if (animated)
        return animatedSprite.getPosition();
    else
        return sprite.getPosition(); // the asteroids are not animated, so this will be called.

}

}

I've spent a few hours on this and I can't seem to figure out what's happening. I think I'm deleting the pointers and their indexes safely, so I don't know where to go from there. For reference, the isColliding function does work with two distinct GameObjects (player and asteroid). It seems like the issue is somehow related to the looping through all asteroids.

Thanks for the help.

UPDATED Asteroid deletion:

int toDelete = -1;
for (int i = 0; i < asteroids.size(); i++) {
    asteroids.at(i)->update(dt);

    if (asteroids.at(i)->getPosition().y > Game::window.getSize().y) {
        toDelete = i;
    }
}

if (toDelete != -1) {
    delete asteroids.at(toDelete);
    asteroids.erase(asteroids.begin() + toDelete);
}

Upvotes: 0

Views: 293

Answers (1)

Rodrigo
Rodrigo

Reputation: 231

You are using iterators to go through the asteroids and then delete them, however the documentation states that after calling erase the iterators are invalidated:

Erase documentation

Iterators, pointers and references pointing to position (or first) and beyond are invalidated, with all iterators, pointers and references to elements before position (or first) are guaranteed to keep referring to the same elements they were referring to before the call.

Hence, after the first call to erase your pointers are no longer valid and anything can happen. Try another strategy for deletion, like identify first the doomed asteroids and then erase them separately.

Upvotes: 1

Related Questions