【问题标题】:C++ Access Violation when executing pointer执行指针时发生 C++ 访问冲突
【发布时间】:2018-04-17 20:07:15
【问题描述】:

我正在使用 c++ 和 sfml 制作一个游戏,其中有小行星从屏幕上掉下来,玩家发射激光来摧毁它们。当小行星或激光离开屏幕时,它们会从各自的 std::vectors 中删除和擦除:

小行星:

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++;
    }
}

激光:

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--;
    }
}

当我尝试检测它们之间的冲突时,问题就出现了。我循环遍历每个激光实例中的所有小行星,并使用父类 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;
    }
}

这里是isColliding和getPosition方法:

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.

}

}

我在这上面花了几个小时,但我似乎无法弄清楚发生了什么。我想我正在安全地删除指针及其索引,所以我不知道从那里去哪里。作为参考,isColliding 函数确实适用于两个不同的游戏对象(玩家和小行星)。似乎这个问题与所有小行星的循环有关。

感谢您的帮助。

更新的小行星删除:

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);
}

【问题讨论】:

  • 你不能像这样遍历一个向量,也不能在上面调用erase
  • 如果asteroids为空,那么i &lt; Game::spawner-&gt;asteroids.size() - 1为真!

标签: c++ pointers sfml access-violation


【解决方案1】:

您正在使用迭代器遍历小行星然后删除它们,但是文档指出在调用 erase 后迭代器无效:

Erase documentation

指向position(或first)及之后的迭代器、指针和引用无效,所有指向position(或first)之前元素的迭代器、指针和引用都保证继续引用它们之前引用的相同元素打电话。

因此,在第一次调用擦除指针后,您的指针不再有效,任何事情都可能发生。尝试另一种删除策略,例如先识别注定要毁灭的小行星,然后将它们分别抹去。

【讨论】:

  • 是否可以调整迭代器(或者在激光的情况下,索引变量)不只是调整以解决擦除问题?例如,我只在它不删除条目时才增加它。 erase() 不会改变向量中的顺序条目,对吧?
  • 不,无法调整迭代器以解决擦除问题,这不是它的工作原理。在您调用擦除之后,迭代器变得无效,您无能为力。您可以尝试解决这个问题,您可能会找到一个有效的职位,但这不是他们应该使用的方式,因此没有任何保证。
  • 我现在正在删除循环外的小行星,但问题仍然存在。这两个错误仍然发生,看似随机的时间。我在原始问题中包含了更新的代码。
  • 仅通过查看很难判断,但是地址 0x00000000 上的访问冲突意味着您正在传递一个空指针。我建议您使用智能指针来处理分配/取消分配。
猜你喜欢
  • 1970-01-01
  • 2018-11-02
  • 2022-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-02
  • 1970-01-01
相关资源
最近更新 更多