ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

ROS generic subscriber as a class method

asked 2018-08-30 04:50:42 -0600

teshansj gravatar image

updated 2018-08-30 22:52:59 -0600

Here I am trying this example's subscriber example code from facontidavide and it works fine as it is. However when I put the topicCallback() in a Class, it's instances appear to share its global variables - whether they are public or private.

class Foo{
private:
    std::string _topic;
public:
    Foo(std::map <std::string, std::string>& info)
    {
        _topic = info["topic"];
    };
    void topicCallback(const topic_tools::ShapeShifter::ConstPtr& msg,
                   const std::string &topic_name,
                   RosIntrospection::Parser& parser)
    {
        ---EXAMPLE CODE---
        cout << _topic << endl;
    }
}

main(){
    ---SOME CODE---
    for (auto &info : topics)
    {
        Foo f(info);
        boost::function<void(const topic_tools::ShapeShifter::ConstPtr&) > callback;
        callback = [&parser, &info, &f](const topic_tools::ShapeShifter::ConstPtr& msg)->void
        {
            f.topicCallback(msg, info.at("topic"), parser) ;
        };
        subscribers.push_back( nh.subscribe(info["topic"], 10, callback) );
    }
    ---SOME MORE CODE---
}

When I create several instances of the class and subscribe to the callback just as in the example code, _topic appears to be the same for all instances. Actually it is the topic of the last instance I create.

This probably might be due to my little understanding of C++11. It'd be a great help if someone could point out what I am doing wrong here.


Edit: Yes it is a C++ related question. But I don't think I'll get an answer by asking this on stackoverflow. I tried using boost::bind instead using a lambda. But it gives some unrecognizable errors like error: use of deleted function xxx May be due to the callback expecting a topic_tools::ShapeShifter for all message types?

edit retag flag offensive close merge delete

Comments

I have a feeling this has more to with your use of the lambda there and how you are capturing the context than with anything ROS related.

gvdhoorn gravatar image gvdhoorn  ( 2018-08-30 05:19:21 -0600 )edit

2 Answers

Sort by » oldest newest most voted
3

answered 2018-08-31 00:24:16 -0600

ahendrix gravatar image

You create Foo f(info) as a local, and then it goes out of scope and is destructed. However, you're also capturing a reference to f within your lambda, and when f goes out of scope you now have a dangling reference.

You should hold onto all of your Foo objects; maybe make them own their subscriber and then keep them in an array somewhere, instead of just holding onto the subscriber objects.

class Foo {
  public:
    Foo(ros::NodeHandle& nh, std::string topic, RosIntrospection::Parser& parser) 
     : topic_(topic)
     , parser_(parser)
     , subscriber_(nh.subscribe(topic, 10, &Foo::topicCallback, this))
    {
    }

    void topicCallback(const topic_tools::ShapeShifter::ConstPtr& msg)
    {
        ---EXAMPLE CODE---
        cout << _topic << endl;
    }
  private:
    std::string topic_;
    RosIntrospection::Parser& parser_;
    ros::Subscriber subscriber_;
};

main(){
    ---SOME CODE---
    std::vector<Foo> foos;
    for (auto &info : topics)
    {
        foos.emplace_back( nh, info["topic"], parser );
    }
    ---SOME MORE CODE---
}
edit flag offensive delete link more

Comments

Thanks. This makes more sense. I tried this but still I get use of deleted function errors. This is the only thing I found from the compiler output that makes sense. note: ‘RosIntrospection::details::Tree...’ is implicitly deleted because the default definition would be ill-formed

teshansj gravatar image teshansj  ( 2018-08-31 04:09:22 -0600 )edit

Errors I get from this is very much similar to the errors I get from using boost::bind. Nothing makes sense. use of deleted functions everywhere

teshansj gravatar image teshansj  ( 2018-08-31 04:11:28 -0600 )edit
1

You write yourself that you have "little understanding of C++11" and this really seems like a C++ issue. If nothing makes sense then it would perhaps be good to first get a bit of a better grip on the C++ concepts that you're trying to use?

gvdhoorn gravatar image gvdhoorn  ( 2018-08-31 05:49:06 -0600 )edit
0

answered 2018-08-31 08:32:01 -0600

teshansj gravatar image

updated 2018-09-03 03:18:57 -0600

Found out what caused the error: use of deleted function xxx errors on @ahendrix 's answer. RosIntrospection::Parser instance can't be copied (similar to std::map instances). You can't do parser1 = parser2;. I don't have a deep understanding on how this happens but if someone come across a similar issue, hope this'll be of help.

Below is my working solution. For my application, I don't need to pass the parser from main so I am using a local parser for each class instance.

class Foo {
  public:
    Foo(std::string topic) 
     : topic_(topic)
    {
        ros::NodeHandle n;
        sub = n.subscribe(topic_, 10, &Foo::topicCallback, this);
    }

    void topicCallback(const topic_tools::ShapeShifter::ConstPtr& msg)
    {
        ---EXAMPLE CODE---
    }
  private:
    std::string topic_;
    RosIntrospection::Parser& parser;
    ros::Subscriber sub;
};

main(){
    ---SOME CODE---
    Foo *f;
    std::vector<Foo*> foos;
    for (auto &info : topics)
    {
        f = new Foo(info);
        foos.push_back(f);
    }
    ---SOME MORE CODE---
}
edit flag offensive delete link more

Question Tools

3 followers

Stats

Asked: 2018-08-30 04:50:42 -0600

Seen: 1,604 times

Last updated: Sep 03 '18