ROS Nodelet封装TestNode时boost shared_ptr空指针错误求助
问题分析与解决
错误原因
你遇到的断言错误是因为test_nodelet.cpp中的boost::shared_ptr<test::TestNode> node_未初始化,直接调用node_->init()时触发了boost空指针检查。同时你的TestNode采用单例模式设计,和nodelet的实例化逻辑存在冲突,需要调整两者的结合方式。
错误信息
nodelet: /usr/include/boost/smart_ptr/shared_ptr.hpp:734: typename boost::detail::sp_member_access::type boost::shared_ptr::operator->() const [with T = test::TestNode; typename boost::detail::sp_member_access::type = test::TestNode*]: Assertion `px != 0' failed.
修复步骤
1. 调整TestNode的设计,适配nodelet节点句柄
原TestNode使用默认构造的全局节点句柄,nodelet需要使用自身的私有节点句柄来保证命名空间和资源隔离,因此修改TestNode的构造函数和单例方法:
修改后的test.h
#ifndef TEST_NODE_H_ #define TEST_NODE_H_ #include <test/TuningConfig.h> #include <cv_bridge/cv_bridge.h> #include <dynamic_reconfigure/server.h> #include <ros/ros.h> #include <sensor_msgs/Image.h> #include <sensor_msgs/RegionOfInterest.h> #include <sensor_msgs/image_encodings.h> #include <opencv2/opencv.hpp> namespace test { class TestNode { public: TestNode(ros::NodeHandle& nh, const std::string& cameraName); static TestNode& GetInstance(ros::NodeHandle& nh, const std::string& cameraName = ""); bool init(); void SetCurrentImage(const cv::Mat& img); // 补充之前缺失的函数 private: ros::NodeHandle nh; ros::Subscriber imageSub; ros::Publisher imagePub; cv::Mat currentImage; // 补充存储图像的成员变量 void InputImageCallback(const sensor_msgs::Image::ConstPtr& msg); const std::string cameraName; }; } // namespace test #endif // TEST_NODE_H_
修改后的test_node.cpp
#include <test/test_node.h> namespace test { TestNode& TestNode::GetInstance(ros::NodeHandle& nh, const std::string& cameraName) { static TestNode instance(nh, cameraName); return instance; } TestNode::TestNode(ros::NodeHandle& nh, const std::string& cameraName) : nh(nh), cameraName(cameraName){}; bool TestNode::init() { imageSub = nh.subscribe(cameraName + "/image_raw", 10, &TestNode::InputImageCallback, this); imagePub = nh.advertise<sensor_msgs::Image>(cameraName + "/final_image", 100); return true; } void TestNode::InputImageCallback(const sensor_msgs::Image::ConstPtr& msg) { cv_bridge::CvImageConstPtr cvPtr = cv_bridge::toCvShare(msg, sensor_msgs::image_encodings::BGR8); SetCurrentImage(cvPtr->image); } void TestNode::SetCurrentImage(const cv::Mat& img) { currentImage = img; } }
2. 修复nodelet的初始化逻辑
去掉未初始化的shared_ptr,直接通过单例方法获取TestNode实例,并传入nodelet的私有节点句柄:
修改后的test_nodelet.cpp
#include "test/test_node.h" #include "nodelet/nodelet.h" #include "pluginlib/class_list_macros.h" namespace test { class TestNodelet : public nodelet::Nodelet { public: TestNodelet(){}; ~TestNodelet(){} virtual void onInit() { ros::NodeHandle& nh = this->getPrivateNodeHandle(); std::string name = nh.getUnresolvedNamespace(); int pos = name.find_last_of('/'); name = name.substr(pos + 1); // 获取TestNode单例实例并初始化 test::TestNode& node = test::TestNode::GetInstance(nh, name); if (node.init()) { NODELET_INFO_STREAM("Initialised. [" << name << "]"); } else { NODELET_ERROR_STREAM("Couldn't initialise. ["<< name << "]"); } } }; } // namespace test PLUGINLIB_EXPORT_CLASS(test::TestNodelet, nodelet::Nodelet);
关键说明
- 单例模式下,
TestNode的全局实例只会被创建一次,后续调用GetInstance会返回同一个实例,确保资源不重复创建。 - 使用nodelet提供的
getPrivateNodeHandle()保证节点在正确的命名空间下运行,避免和其他节点或nodelet的资源冲突。 - 补充了原代码中缺失的
SetCurrentImage函数和对应的成员变量,修复回调函数中的错误调用。
内容的提问来源于stack exchange,提问作者waka_linux
相关产品推荐
相关产品推荐

