ROS2中类构造传this引发std::bad_weak_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>
解决方案
原因分析
- 原始错误:
shared_from_this()只能在对象被shared_ptr管理之后调用,构造函数执行时,std::make_shared<IkArm>还未完成对象初始化,此时没有对应的shared_ptr关联,因此触发std::bad_weak_ptr。 - 修改后的错误:
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
相关产品推荐
相关产品推荐

