You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

游戏开发中使用list.remove_if()导致程序崩溃的问题求助

问题分析

崩溃的核心原因是在遍历列表的同时修改列表:

  • 你用的范围for循环依赖迭代器遍历brainFrag列表,但调用remove_if会直接删除列表元素,导致当前迭代器失效。后续循环继续访问已被销毁的元素(内存标记0xDDDDDDE9是VS中已释放堆内存的标识),触发读访问违规。
  • 额外问题:remove_if的lambda按值捕获rect、参数按值传递sf::RectangleShape val,会产生不必要的对象拷贝;直接用==比较浮点数类型的位置,可能因精度误差导致误判。
修复方案

方案1:安全遍历并删除单个碰撞元素(推荐)

使用迭代器遍历,删除元素时利用erase的返回值更新迭代器,避免失效:

auto it = world1.level1.brainFrag.begin();
while (it != world1.level1.brainFrag.end()) {
    if (milo.sprite.getGlobalBounds().intersects(it->getGlobalBounds())) {
        // erase返回下一个有效迭代器,直接赋值给it继续循环
        it = world1.level1.brainFrag.erase(it);
        brainFrag -= 1;
    } else {
        ++it;
    }
}

方案2:先记录碰撞位置,再批量删除

如果需要删除所有位置相同的收集物,先遍历找到碰撞位置,再统一执行删除:

sf::Vector2f collidedPos;
bool collided = false;

// 先遍历检测碰撞,记录位置
for (const auto& rect : world1.level1.brainFrag) {
    if (milo.sprite.getGlobalBounds().intersects(rect.getGlobalBounds())) {
        collidedPos = rect.getPosition();
        collided = true;
        break; // 若要处理多个碰撞,可改为收集所有位置
    }
}

if (collided) {
    // 用误差范围比较浮点数位置,避免精度问题
    world1.level1.brainFrag.remove_if([collidedPos](const sf::RectangleShape& val) {
        const float eps = 0.01f;
        return std::abs(val.getPosition().x - collidedPos.x) < eps &&
               std::abs(val.getPosition().y - collidedPos.y) < eps;
    });
    // 若删除多个元素,建议直接用列表size计算剩余数量,避免手动维护brainFrag变量
    // brainFrag = world1.level1.brainFrag.size();
    brainFrag -= 1;
}
额外优化建议
  • 避免手动维护brainFrag计数,直接用world1.level1.brainFrag.size()获取当前收集物数量,防止计数与实际列表元素不一致。
  • 碰撞检测时,尽量使用const&引用遍历元素,减少不必要的对象拷贝。

内容的提问来源于stack exchange,提问作者oshiwota

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 18:49:11