C++ 避坑指南:ROS 回调函数中的对象生命周期陷阱 (Use-After-Free)
在将 ROS2 代码迁移回 ROS1,或者编写基于类的 ROS 节点时,对象的生命周期管理是一个极其隐蔽但致命的杀手。
最近在调试一个多传感器融合系统时,我遇到了一个非常典型的 Segmentation Fault (段错误)。这个问题在只订阅一个话题时'偶尔正常',一旦增加第二个订阅者就立即崩溃。
本文将复盘这次 Debug 过程,深入分析 C++ 智能指针、ROS 回调机制与内存管理的深层关系。
1. 问题现场:诡异的 Mutex 崩溃
程序运行后,在接收到雷达点云消息的瞬间崩溃。GDB 调试生成的堆栈信息如下:
#0 __GI___pthread_mutex_lock (mutex=0x72) at ../nptl/pthread_mutex_lock.c:67
#1 0x00007ffff7f5ece9 in ThreadSafeDeque<...>::push_back(...)
#2 0x00007ffff7f67f6e in PointCloudSubscriber::topic_callback(...)
...
#10 0x0000555555569608 in main ()
关键线索:
- 崩溃发生在
callback回调函数内部。 - 死因是
pthread_mutex_lock,且mutex=0x72。 0x72显然不是一个合法的堆内存地址(通常是很大的数值),这说明 互斥锁所在的内存地址被踩踏(Memory Stomping)了,或者我们访问了一个已经释放的对象。
2. 问题代码复现
为了封装 ROS 的发布订阅功能,我设计了一个 ROSPubSub 类。崩溃的代码逻辑简化如下:
// 错误的写法
void ROSPubSub::addSubscriber(const std::string& topic_name, const DataType& type, ...) {
if (type == DataType::LIDAR) {
// 1. 创建一个订阅者包装类对象 (使用智能指针)
auto node = std::make_shared<PointCloudSubscriber>(nh, topic_name, ...);
// 2. 将 ROS 的 Subscriber 句柄保存到 map 中
// 注意:node->subscriber_ 是一个 ros::Subscriber 对象
->subscriber_nodes[topic_name] = node->subscriber_;
}
}


