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 ...
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?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.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
.