You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

类构造函数中初始化tf::MessageFilter对象触发std::bad_alloc错误,改用指针则正常的代码差异分析

为什么第一种PoseDrawer实现会触发std::bad_alloc,而指针版本能正常运行?

咱们先直接说核心差异,再拆解背后的原因:

核心差异

  • 第一个实现中,tf_filter_是类的成员对象,在构造函数的初始化列表中直接完成初始化;
  • 第二个实现中,tf_filter_是指针类型的成员,在构造函数函数体内部通过new动态分配并初始化。

为什么第一个版本会抛出std::bad_alloc?

问题出在C++类成员的初始化顺序规则上:C++类的成员是按照它们在类中声明的顺序来初始化的,和构造函数初始化列表里写的顺序完全无关!

咱们看第一个版本的成员声明顺序:

private: 
  message_filters::Subscriber<geometry_msgs::PointStamped> point_sub_; 
  tf::TransformListener tf_; 
  tf::MessageFilter<geometry_msgs::PointStamped> tf_filter_; 
  ros::NodeHandle n_; 
  std::string target_frame_; 

实际初始化顺序是:point_sub_ → tf_ → tf_filter_ → n_ → target_frame_

而你在构造函数初始化列表里写的顺序是:

PoseDrawer() : tf_(), target_frame_("turtle1"), tf_filter_(point_sub_, tf_, target_frame_, 10)

看起来你是先初始化tf_和target_frame_再处理tf_filter_,但C++会严格按声明顺序执行:

  1. 先默认初始化point_sub_
  2. 接着初始化tf_
  3. 直接开始初始化tf_filter_——这时候就出问题了:
    • n_还没初始化(因为它在tf_filter_之后声明),你后续才会在构造函数体里调用point_sub_.subscribe(n_, ...),所以此时point_sub_是未完成订阅的无效状态;
    • target_frame_也还没初始化(同样因为声明顺序靠后),把一个未初始化的std::string传给tf_filter_的构造函数,会导致内部内存操作出现非法行为,最终触发std::bad_alloc(本质是非法内存访问引发的分配失败)。

为什么第二个版本能正常运行?

把tf_filter_改成指针后,初始化逻辑完全变了:

  1. 构造函数初始化阶段,只会处理非指针成员:point_sub_、tf_、n_、target_frame_都会按声明顺序完成默认/指定初始化;
  2. 进入构造函数体后,你先调用point_sub_.subscribe(n_, ...)——此时n_已经完全初始化,point_sub_能正常完成订阅;
  3. 最后通过new创建tf_filter_,此时传入的point_sub_(已订阅)、tf_(已初始化)、target_frame_(已赋值)都是完全有效的状态,自然不会出现内存分配错误。

说白了就是:第一个版本踩了C++初始化顺序的坑,用指针延迟初始化就完美避开了这个问题。

内容的提问来源于stack exchange,提问作者b3hn4m

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 10:27:32