类成员std::multimap堆分配指针的内存错误与崩溃排查
问题解答
1. 栈变量指针存入栈multimap导致野指针问题
核心问题是栈内存生命周期不匹配:OnEnter方法中的iterHolder是栈变量,方法执行完毕离开作用域时,栈上的iterHolder会被系统自动销毁,此时存在std::multimap里的指针就指向了已释放的垃圾内存,后续访问必然触发未定义行为。
解决办法:
- 若
Handle需要长期存活(超出OnEnter方法生命周期),将iterHolder改为堆分配:Handle* iterHolder = new Handle(...);,后续需在合适时机手动释放该对象。 - 若
Handle无需长期存活且支持拷贝/移动,直接在multimap中存储Handle对象而非指针:std::multimap<Player*, Handle>,从根源避免指针悬空问题。
2. 单例模式下堆分配multimap指针未初始化导致崩溃
使用shared_instance()(单例模式)时,程序会调用DamageBox的默认构造函数,但你仅在带参构造函数中初始化了heapTest指针,默认构造函数中heapTest是未初始化的野指针,调用emplace时会访问空指针的内部结构,从而触发_Scary->_Myhead为nullptr的读取访问违规。
解决办法:
- 方案一:补全默认构造函数的初始化
在默认构造函数中手动初始化堆指针:class DamageBox { private: std::multimap<Player*, Handle*>* heapTest; DamageBox() : heapTest(new std::multimap<Player*, Handle*>()) {} // 带参构造函数保持原有逻辑 public: static DamageBox& shared_instance() { static DamageBox instance; return instance; } // 其他成员方法... }; - 方案二:直接使用栈上的multimap(更简洁)
单例对象本身是静态存储(或堆分配),其成员变量的生命周期与单例一致,因此直接用栈上的multimap作为成员即可,无需堆分配指针:class DamageBox { private: std::multimap<Player*, Handle*> testMap; DamageBox() = default; public: static DamageBox& shared_instance() { static DamageBox instance; return instance; } // OnEnter方法中直接操作testMap即可 }; - 方案三:用智能指针管理堆分配的multimap
避免手动管理内存,使用std::unique_ptr自动完成初始化和释放:class DamageBox { private: std::unique_ptr<std::multimap<Player*, Handle*>> heapTest; DamageBox() : heapTest(std::make_unique<std::multimap<Player*, Handle*>>()) {} public: static DamageBox& shared_instance() { static DamageBox instance; return instance; } };
3. new创建的Handle对象erase时delete是否足够
满足以下两个条件时,erase键值对时delete对应的Handle指针可以完成内存释放:
- 每个
Handle指针都是通过new单独分配,且没有被其他地方的指针引用(无共享所有权); - 每个
Handle指针只会被delete一次(比如multimap中不会重复存储同一个Handle指针,或erase时确保只执行一次delete)。
但更推荐用智能指针替代裸指针,比如将multimap改为std::multimap<Player*, std::unique_ptr<Handle>>。这样erase键值对时,std::unique_ptr会自动调用delete释放内存,无需手动操作,彻底规避内存泄漏和重复释放的风险:
// 存入对象 testMap.emplace(playerPtr, std::make_unique<Handle>(...)); // 删除键值对时自动释放内存 testMap.erase(playerPtr);
内容的提问来源于stack exchange,提问作者DSiegmeyer
相关产品推荐
相关产品推荐

