0
$\begingroup$

When coding with ROS2, I would sometimes make a class whose constructor needs a rclcpp::Node::SharedPtr. Then, I would make this class be a member of a parent Node class. So something like:

class Foo
{
    Foo(rclcpp::Node::SharedPtr nh)
    {}
};

class ParentNode : public rclcpp::Node
{
public:
    ParentNode()
    : Node("parent_node")
    , foo(shared_from_this())
    {}
private:
    Foo foo
}

However, I cannot call shared_from_this() inside the constructor (it throws a weak_ptr error).

I have seen others get away with it by having LifecycleNode as the parent and initializing the foo inside the on_configure() method.

Is there another way to make this work or is this just bad programming pattern?

I currently have two solutions:

  1. Instead of taking a Node::SharedPtr, the Foo class would take Node* and you can pass this in the constructor
class Foo
{
    Foo(rclcpp::Node* nh)
    {}
};

class ParentNode : public rclcpp::Node
{
public:
    ParentNode()
    : Node("parent_node")
    , foo(this)
    {}
private:
    Foo foo
}
  1. Make a rclcpp::TimerBase to run a function that initializes foo after the constructor
class Foo
{
    Foo()
    {}

    Foo(rclcpp::Node::SharedPtr nh)
    {}
};

class ParentNode : public rclcpp::Node
{
public:
    ParentNode()
    : Node("parent_node")
    {
        timer_ = this->create_wall_timer(
            500ms, std::bind(&ParentNode::initialize, this)
        );
    }
private:
    Foo foo
    rclcpp::TimerBase::SharedPtr timer_;

    void initialize()
    {
        timer_->cancel();
        foo = Foo(shared_from_this());
    }
}
```
$\endgroup$

1 Answer 1

0
$\begingroup$

Actually quite interesting.

Following this stack overflow post, your object must first exist before you can have a pointer pointing towards it or owning it. Since you make_shared or assign new an instance of your class ParentNode (at some point in your main), shared_from_this() cannot return anything inside the constructor, because your ParentNode object does not exist yet.

As a workaround, I would not use the raw pointer or a timer that you bind a callback to. Just add a public function that does the initialization and call it after your make_shared on the object as instance_shared_ptr->initialize();. Of course, some safeguards inside your class would be good, checking if(!foo) return; before you let it do anything.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.