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

ROS2中类构造传this引发std::bad_weak_ptr及编译错误求助

问题:ROS2中类构造时传递shared_ptr的错误解决

我需要将IkArm类的自身shared_ptr传入IkSolver类的构造函数,但直接在IkArm构造函数中调用shared_from_this()会触发错误,尝试拆分初始化逻辑后又遇到类型转换问题,具体情况如下:

原始代码

#include "rclcpp/rclcpp.hpp"

class IkSolver
{
    public:
        IkSolver(std::shared_ptr<rclcpp::Node> node) : node_(node)
        {
            RCLCPP_INFO(node_->get_logger(), "2nd Constructor");                
        }

    private:
        std::shared_ptr<rclcpp::Node> node_;
};

class IkArm : public rclcpp::Node
{
    public:
        IkArm() : Node("IkNode")
        {
            RCLCPP_INFO(this->get_logger(), "1st Constructor");
            
            obj1_ = std::make_shared<IkSolver>(shared_from_this());
            RCLCPP_INFO(this->get_logger(), "Back To 1st Constructor");
        }

    private:
        std::shared_ptr<IkSolver> obj1_;
};


int main(int argc, char * argv[])
{
    rclcpp::init(argc, argv);
    rclcpp::spin(std::make_shared<IkArm>());
    rclcpp::shutdown();
    return 0;
}

原始报错

[INFO] [1720452645.004303274] [IkNode]: 1st Constructor
terminate called after throwing an instance of 'std::bad_weak_ptr'
  what():  bad_weak_ptr
[ros2run]: Aborted

修改后代码

#include "rclcpp/rclcpp.hpp"

class IkSolver
{
    public:
        IkSolver(std::shared_ptr<rclcpp::Node> node) : node_(node)
        {
            RCLCPP_INFO(node_->get_logger(), "2nd Constructor");                
        }

    private:
        std::shared_ptr<rclcpp::Node> node_;
};

class IkArm : public rclcpp::Node
{
    public:
        IkArm() : Node("IkNode")
        {
            RCLCPP_INFO(this->get_logger(), "1st Constructor");
            
            RCLCPP_INFO(this->get_logger(), "Back To 1st Constructor");
        }

        std::shared_ptr<IkArm> init()
        {
            obj1_ = std::make_shared<IkSolver>(shared_from_this());
            return shared_from_this();
        }

    private:    
        std::shared_ptr<IkSolver> obj1_;
};


int main(int argc, char * argv[])
{
    rclcpp::init(argc, argv);
    rclcpp::spin(std::make_shared<IkArm>()->init());
    rclcpp::shutdown();
    return 0;
}

修改后编译报错

error: could not convert ‘std::enable_shared_from_this<_Tp>::shared_from_this() [with _Tp = rclcpp::Node]()’ from ‘shared_ptr<rclcpp::Node>’ to ‘shared_ptr<IkArm>’
   32 |             return shared_from_this();
      |                    ~~~~~~~~~~~~~~~~^~
      |                                    |
      |                                    shared_ptr<rclcpp::Node>

解决方案

原因分析

  1. 原始错误:shared_from_this()只能在对象被shared_ptr管理之后调用,构造函数执行时,std::make_shared<IkArm>还未完成对象初始化,此时没有对应的shared_ptr关联,因此触发std::bad_weak_ptr。
  2. 修改后的错误:IkArm继承自rclcpp::Node,而rclcpp::Node本身继承了std::enable_shared_from_this<rclcpp::Node>,所以shared_from_this()返回的是shared_ptr<rclcpp::Node>,无法直接隐式转换为shared_ptr<IkArm>。

修正方案

方案1:修正类型转换问题

在init()方法中,使用std::static_pointer_cast将基类的shared_ptr转换为派生类的shared_ptr:

#include "rclcpp/rclcpp.hpp"
#include <memory> // 确保包含static_pointer_cast所需头文件

class IkSolver
{
    public:
        IkSolver(std::shared_ptr<rclcpp::Node> node) : node_(node)
        {
            RCLCPP_INFO(node_->get_logger(), "2nd Constructor");                
        }

    private:
        std::shared_ptr<rclcpp::Node> node_;
};

class IkArm : public rclcpp::Node
{
    public:
        IkArm() : Node("IkNode")
        {
            RCLCPP_INFO(this->get_logger(), "1st Constructor");
        }

        std::shared_ptr<IkArm> init()
        {
            // 创建IkSolver时,shared_from_this()返回的shared_ptr<Node>可以直接传入,无需转换
            obj1_ = std::make_shared<IkSolver>(shared_from_this());
            // 将基类shared_ptr转换为派生类
            return std::static_pointer_cast<IkArm>(shared_from_this());
        }

    private:    
        std::shared_ptr<IkSolver> obj1_;
};


int main(int argc, char * argv[])
{
    rclcpp::init(argc, argv);
    rclcpp::spin(std::make_shared<IkArm>()->init());
    rclcpp::shutdown();
    return 0;
}

方案2:使用工厂方法(更安全)

通过静态工厂方法创建IkArm,确保对象完全被shared_ptr管理后再初始化IkSolver:

#include "rclcpp/rclcpp.hpp"
#include <memory>

class IkSolver
{
    public:
        IkSolver(std::shared_ptr<rclcpp::Node> node) : node_(node)
        {
            RCLCPP_INFO(node_->get_logger(), "2nd Constructor");                
        }

    private:
        std::shared_ptr<rclcpp::Node> node_;
};

class IkArm : public rclcpp::Node
{
    // 构造函数设为私有,只能通过工厂方法创建
    private:
        IkArm() : Node("IkNode")
        {
            RCLCPP_INFO(this->get_logger(), "1st Constructor");
        }

    public:
        static std::shared_ptr<IkArm> create()
        {
            // 先创建shared_ptr管理IkArm对象
            auto arm = std::shared_ptr<IkArm>(new IkArm());
            // 此时可以安全调用shared_from_this()
            arm->obj1_ = std::make_shared<IkSolver>(arm->shared_from_this());
            RCLCPP_INFO(arm->get_logger(), "Back To 1st Constructor");
            return arm;
        }

    private:    
        std::shared_ptr<IkSolver> obj1_;
};


int main(int argc, char * argv[])
{
    rclcpp::init(argc, argv);
    rclcpp::spin(IkArm::create());
    rclcpp::shutdown();
    return 0;
}

关键说明

  • shared_from_this()的调用前提是对象已经被std::shared_ptr持有,因此必须在构造完成后调用。
  • 当派生类继承自一个已经使用std::enable_shared_from_this的基类时,需要显式转换shared_ptr类型,因为shared_from_this()会返回基类的指针。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 02:23:18