Trouble Reading Back Array of Characters
In order to accommodate an encoded string that might have a terminal character, I'm trying to pass the data as a custom message with a char array rather than a standard string. Everything in the publisher seems to be fine, but when I try to read the array back using an iterator the error seems to tell me that the array entry is no longer the std::vector<char>
that I expected, but now a std::vector<unsigned char, std::allocator<unsigned char> >::iterator
that I can't assign to the iterator type I want to use.
This is my custom message, EncodedString.msg:
char[] data
int32 length
and this is the subscriber code where I try to read it back out:
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "tutorial_interfaces/msg/encoded_string.hpp"
class MinimalSubscriber : public rclcpp::Node
{
public:
MinimalSubscriber()
: Node("minimal_subscriber")
{
subscription_ = this->create_subscription<tutorial_interfaces::msg::EncodedString>(
"topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, std::placeholders::_1));
}
private:
void topic_callback(const tutorial_interfaces::msg::EncodedString::SharedPtr msg) const
{
int char_length = msg->length;
std::string encoded_bytes = "";
std::vector<char>::iterator char_it;
for( char_it = msg->data.begin(); msg->data.end(); char_it++ )
{
encoded_bytes.append( msg->data[char_it] );
}
}
rclcpp::Subscription<tutorial_interfaces::msg::EncodedString>::SharedPtr subscription_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalSubscriber>());
rclcpp::shutdown();
return 0;
}
If it looks familiar, it's because I'm using the standard publisher/subscriber to test the concept before I do anything more complicated, so hopefully this is a proper minimal example. The problem arises when I go to build the package, and the first error that I get is:
Starting >>> cpp_pubsub
--- stderr: cpp_pubsub
/home/teddybouch/workspace/ros2_ws/src/cpp_pubsub/src/subscriber_member_function.cpp: In member function ‘void MinimalSubscriber::topic_callback(tutorial_interfaces::msg::EncodedString_<std::allocator<void> >::SharedPtr) const’:
/home/teddybouch/workspace/ros2_ws/src/cpp_pubsub/src/subscriber_member_function.cpp:45:36: error: no match for ‘operator=’ (operand types are ‘std::vector<char>::iterator’ {aka ‘__gnu_cxx::__normal_iterator<char*, std::vector<char> >’} and ‘std::vector<unsigned char, std::allocator<unsigned char> >::iterator’ {aka ‘__gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char, std::allocator<unsigned char> > >’})
45 | for( char_it = msg->data.begin(); msg->data.end(); char_it++ )
| ^
In file included from /usr/include/c++/9/bits/stl_algobase.h:67,
from /usr/include/c++/9/memory:62,
from /home/teddybouch/workspace/ros2_ws/src/cpp_pubsub/src/subscriber_member_function.cpp:15:
/usr/include/c++/9/bits/stl_iterator.h:784:11: note: candidate: ‘constexpr __gnu_cxx::__normal_iterator<char*, std::vector<char> >& __gnu_cxx::__normal_iterator<char*, std::vector<char> >::operator=(const __gnu_cxx::__normal_iterator<char*, std::vector<char> >&)’
784 | class __normal_iterator
| ^~~~~~~~~~~~~~~~~
/usr/include/c++/9/bits/stl_iterator.h:784:11: note: no known conversion for argument 1 from ‘std::vector<unsigned char, std::allocator<unsigned char> >::iterator’ {aka ‘__gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char, std::allocator<unsigned char> > >’} to ‘const __gnu_cxx::__normal_iterator<char*, std::vector<char> >&’
/usr/include/c++/9/bits/stl_iterator.h:784:11: note: candidate: ‘constexpr __gnu_cxx::__normal_iterator<char*, std::vector<char> >& __gnu_cxx::__normal_iterator<char*, std::vector<char> >::operator=(__gnu_cxx::__normal_iterator<char*, std::vector<char> >&&)’
/usr/include/c++/9/bits/stl_iterator.h:784:11: note: no known conversion for argument 1 from ‘std::vector<unsigned char, std::allocator<unsigned char> >::iterator’ {aka ‘__gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char, std::allocator<unsigned char> > >’} to ‘__gnu_cxx::__normal_iterator<char*, std::vector<char> >&&’
Can someone please clarify what is going on here for me?
Asked by teddybouch on 2022-05-23 23:08:52 UTC
Answers
According to http://design.ros2.org/articles/idl_interface_definition.html, by definition a char
is unsigned in ros2.
In c++, a char
is either signed or unsigned, whichever the compiler-writer decided to use. You (the developer) are responsible for handling the mismatch, if there is one.
Asked by Mike Scheutzow on 2022-05-24 06:38:32 UTC
Comments
Out of curiosity: what are you publishing that "is a string, but might contain a terminal character"?
Is it a binary payload? Would a plain unbounded
uint8
array not be a better fit in that case?Asked by gvdhoorn on 2022-05-24 02:03:44 UTC
I'm using DCCL to encode and decode protobufs, which outputs a string but in practice I've found will sometimes only pass part of the string when sent as a standard string message. I need to get it back into a string to decode on the other end, so using a
char[]
seemed more straightforward than dealing with the conversions to use auint8[]
. I may end up using the latter and can mess around with that option after work, but either way I think that it's worth my figuring out what's going on here that I can't get thechar[]
back on the subscriber end.Asked by teddybouch on 2022-05-24 04:45:36 UTC
an actual
std::string
, or aconst char*
or something similar?In both cases sending that as a
char[]
field in a ROS message doesn't seem like it would be appropriate.Having written that though: the error message basically tells you the iterator type is incompatible.
ROS messages use a configurable allocator, and the type of the iterator defined for the message type carries that type with it. You'll either have to match the type, or use
auto
.Asked by gvdhoorn on 2022-05-24 06:53:31 UTC