C++ std::list存储Object派生类指针删除后无法移除元素报错
问题原因
- 你在范围for循环遍历
std::list的过程中直接调用remove()修改容器结构,会导致当前迭代器及后续迭代器全部失效,触发未定义行为,大部分符合删除条件的元素没有被遍历到,自然无法从列表中移除。 - 基类
Object没有声明虚析构函数,通过基类指针删除派生类Player对象时会出现析构不完全的问题,存在内存泄漏隐患。 - 你先执行
delete obj释放了对象内存,虽然指针本身的地址值没有改变,remove()可以匹配到对应元素,但如果后续逻辑不小心访问该指针指向的内存,就会触发野指针访问崩溃。
修复方案
推荐使用std::list自带的remove_if接口实现删除逻辑,该接口原生支持遍历过程中安全移除元素,是最高效且符合标准的写法,修改步骤如下:
- 给基类
Object添加虚析构函数,保证派生类对象可以被正确析构:
class Object { public: bool needs_delete = false; virtual void tick() {} virtual void render() {} // 新增虚析构函数 virtual ~Object() = default; };
- 把主函数中原来的删除逻辑范围for循环,替换为
remove_if实现:
// 替换原有的删除逻辑for循环 myObjs->remove_if([](Object* obj) { if (obj->needs_delete) { std::cout << "deleted object\n"; delete obj; return true; } return false; });
额外优化建议
你不需要动态创建std::list对象,直接在栈上分配即可,避免不必要的堆内存管理开销:
把std::list<Object*>* myObjs = new std::list<Object*>;修改为std::list<Object*> myObjs;,后续所有myObjs->调用都改为myObjs.即可。
内容的提问来源于stack exchange,提问作者Sandu Chicu
相关产品推荐
相关产品推荐

