游戏开发中使用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
相关产品推荐
相关产品推荐

