C++多线程下使用dynamic_cast转换派生类对象出现数据异常问题
问题根因
你存储到list_fifoGroundEvt队列中的是对象的裸指针,该指针指向的对象生命周期提前结束,导致后续读取时访问的是已经被释放的野内存,出现数值异常:
- 你调用
pushGroundEventFifo(entry)时,若entry是栈上分配的局部临时对象,执行push操作时对象还未销毁,因此断点能看到正确的x、y值; - 当创建
entry的函数执行完成后,栈空间被回收,entry被销毁,队列中存储的指针变成野指针,后续transmit线程读取该指针指向的内存时,内存已经被其他数据覆盖,因此读出来的y值异常。
解决方案
修改对象分配方式,改为堆分配延长对象生命周期,或者改用智能指针自动管理内存:
方案1:堆分配对象(基础修改)
创建entry时使用new在堆上分配内存,避免栈回收导致对象销毁,示例调用逻辑:
// 原来的栈分配写法(错误): // fifoGroundEvtEntry entry; // entry.x = 1; // entry.y = 2; // sender::GetInstance()->getDataCollector()->pushGroundEventFifo(entry); // 修改为堆分配写法(正确): fifoGroundEvtEntry* entry = new fifoGroundEvtEntry(); entry->x = 1; entry->y = 2; sender::GetInstance()->getDataCollector()->pushGroundEventFifo(*entry);
注意要在test方法读取完数据后,手动delete指针避免内存泄漏,修改test方法:
void test() { if (fifoGroundEvtEntry* grdEvt = dynamic_cast<fifoGroundEvtEntry*>(list_fifoGroundEvt.front())) { std::cout << grdEvt ->y << std::endl; } delete list_fifoGroundEvt.front(); // 新增:释放堆内存 list_fifoGroundEvt.pop_front(); }
方案2:使用智能指针(更安全,避免内存泄漏)
修改队列存储类型为std::shared_ptr<fifoEvtEntry>,自动管理对象生命周期,无需手动释放内存:
// 修改collector类的队列定义: private: std::list<std::shared_ptr<fifoEvtEntry>> list_fifoGroundEvt; // 修改push方法: void pushGroundEventFifo(std::shared_ptr<fifoEvtEntry> entry) { if (auto grdEvt = std::dynamic_pointer_cast<fifoGroundEvtEntry>(entry)) { list_fifoGroundEvt.push_back(grdEvt); } } // 调用示例: auto entry = std::make_shared<fifoGroundEvtEntry>(); entry->x = 1; entry->y = 2; sender::GetInstance()->getDataCollector()->pushGroundEventFifo(entry);
其他注意事项
如果后续逻辑改为线程运行过程中同时有push操作,需要给list_fifoGroundEvt的读写操作加互斥锁,避免多线程竞争导致的异常。
内容的提问来源于stack exchange,提问作者anes47
相关产品推荐
相关产品推荐

