What is a void `std::allocator`? ie: `std::allocator<void>`
Asked Answered
R

1

10

Autogenerated ROS (Robot Operating System) message C++ header files contain typedefs like this:

typedef  ::std_msgs::Header_<std::allocator<void> > Header;

What does std::allocator<void> mean here? Why is the template type void? What does it mean? When is it used?

Here is the documentation for std::allocator<>:

  1. https://www.cplusplus.com/reference/memory/allocator/
  2. https://en.cppreference.com/w/cpp/memory/allocator

Here is the example autogenerated file to look at: http://docs.ros.org/en/electric/api/std_msgs/html/msg__gen_2cpp_2include_2std__msgs_2Header_8h_source.html.

That first line above is line 116.

This is the start of the autogenerated ROS message Header_ class:

template <class ContainerAllocator>
struct Header_ {

Here is a little more context from the autogenerated Header.h, with the various typedefs at the bottom:

template <class ContainerAllocator>
struct Header_ {
  typedef Header_<ContainerAllocator> Type;

  Header_()
  : seq(0)
  , stamp()
  , frame_id()
  {
  }

  Header_(const ContainerAllocator& _alloc)
  : seq(0)
  , stamp()
  , frame_id(_alloc)
  {
  }

  typedef uint32_t _seq_type;
  uint32_t seq;

  typedef ros::Time _stamp_type;
  ros::Time stamp;

  typedef std::basic_string<char, std::char_traits<char>, typename ContainerAllocator::template rebind<char>::other >  _frame_id_type;
  std::basic_string<char, std::char_traits<char>, typename ContainerAllocator::template rebind<char>::other >  frame_id;


private:
  static const char* __s_getDataType_() { return "std_msgs/Header"; }
public:
  ROS_DEPRECATED static const std::string __s_getDataType() { return __s_getDataType_(); }

  ROS_DEPRECATED const std::string __getDataType() const { return __s_getDataType_(); }

private:
  static const char* __s_getMD5Sum_() { return "2176decaecbce78abc3b96ef049fabed"; }
public:
  ROS_DEPRECATED static const std::string __s_getMD5Sum() { return __s_getMD5Sum_(); }

  ROS_DEPRECATED const std::string __getMD5Sum() const { return __s_getMD5Sum_(); }

private:
  static const char* __s_getMessageDefinition_() { return "# Standard metadata for higher-level stamped data types.\n\
# This is generally used to communicate timestamped data \n\
# in a particular coordinate frame.\n\
# \n\
# sequence ID: consecutively increasing ID \n\
uint32 seq\n\
#Two-integer timestamp that is expressed as:\n\
# * stamp.secs: seconds (stamp_secs) since epoch\n\
# * stamp.nsecs: nanoseconds since stamp_secs\n\
# time-handling sugar is provided by the client library\n\
time stamp\n\
#Frame this data is associated with\n\
# 0: no frame\n\
# 1: global frame\n\
string frame_id\n\
\n\
"; }
public:
  ROS_DEPRECATED static const std::string __s_getMessageDefinition() { return __s_getMessageDefinition_(); }

  ROS_DEPRECATED const std::string __getMessageDefinition() const { return __s_getMessageDefinition_(); }

  ROS_DEPRECATED virtual uint8_t *serialize(uint8_t *write_ptr, uint32_t seq) const
  {
    ros::serialization::OStream stream(write_ptr, 1000000000);
    ros::serialization::serialize(stream, seq);
    ros::serialization::serialize(stream, stamp);
    ros::serialization::serialize(stream, frame_id);
    return stream.getData();
  }

  ROS_DEPRECATED virtual uint8_t *deserialize(uint8_t *read_ptr)
  {
    ros::serialization::IStream stream(read_ptr, 1000000000);
    ros::serialization::deserialize(stream, seq);
    ros::serialization::deserialize(stream, stamp);
    ros::serialization::deserialize(stream, frame_id);
    return stream.getData();
  }

  ROS_DEPRECATED virtual uint32_t serializationLength() const
  {
    uint32_t size = 0;
    size += ros::serialization::serializationLength(seq);
    size += ros::serialization::serializationLength(stamp);
    size += ros::serialization::serializationLength(frame_id);
    return size;
  }

  typedef boost::shared_ptr< ::std_msgs::Header_<ContainerAllocator> > Ptr;
  typedef boost::shared_ptr< ::std_msgs::Header_<ContainerAllocator>  const> ConstPtr;
  boost::shared_ptr<std::map<std::string, std::string> > __connection_header;
}; // struct Header
typedef  ::std_msgs::Header_<std::allocator<void> > Header;

typedef boost::shared_ptr< ::std_msgs::Header> HeaderPtr;
typedef boost::shared_ptr< ::std_msgs::Header const> HeaderConstPtr;

Related

I believe these are not duplicates:

  1. What is allocator<T> - not a duplicate because I'm asking about the specific case of T is void, not the general case of what is a std::allocator<>.
  2. Deprecation of std::allocator<void> - not a duplicate because I'm not wondering why it has been deprecated or changed in C++20, I'm asking what the std::allocator<void> case is in general, what it does, and when/why to use it.
  3. https://answers.ros.org/question/212857/what-is-constptr/
Roulers answered 12/4, 2021 at 6:18 Comment(12)
Does this answer your question? What is allocator<T> I found it by putting c++ what is a std::allocator into a search engine; does that help?Sunda
@KarlKnechtel This question seems to be specific about T being void, which is kind of special.Katsuyama
@KarlKnechtel, no, I've been googling and reading about std::allocator<> in general for about 1 hr now, but neither that question nor the other sources I've come across mention anything about using void as the template type for it, nor how that affects it.Roulers
@DanielLangr, "It's not that std::allocator<void> is deprecated, just it isn't a explicit specialisation." See: https://mcmap.net/q/646095/-deprecation-of-std-allocator-lt-void-gt.Roulers
This answer might be useful: https://mcmap.net/q/646095/-deprecation-of-std-allocator-lt-void-gt.Katsuyama
@GabrielStaples You're right, only that explicit specialization is deprecated/removed.Katsuyama
@DanielLangr. That is good insight. I think it still begs a lot more explanation though. I still don't have the background nor context to understand that answer.Roulers
Side note: I cringe every time I ask a question on Stack Overflow. I've hardly asked a question where someone hasn't clicked the "close" button, despite me adding quite a few valuable questions with no existing answers. :)Roulers
@GabrielStaples I am not sure whether it is worth trying to understand something related to pre-C++11 problems. I also don't know details, but this is somehow related to allocators rebinding, which is sometimes needed. For example, std::unorder_map takes an allocator type for its value_type. But, internally, the map needs to allocate nodes, so it needs to "rebind" this allocator type to a different value type. This, for example, allows one to use memory pooling for node allocations (one just need to be aware that the allocator is used for the array of buckets as well).Katsuyama
@DanielLangr, "I am not sure whether it is worth trying to understand something related to pre-C++11 problems." The ROS code used above is actively used across many professional code repos, even those using C++17 today, and including my own. I think it merits further understanding, and the work necessary to get there, especially since some subset of users on Stack Overflow surely already know the answer and could provide a great service in sharing their knowledge.Roulers
@GabrielStaples "some subset of users on Stack Overflow surely already know the answer" — I wouldn't be that optimistic. The answer may actually be known only by ROS developer who wrote that auto-generating code. StackOverflow users may give you some generic answer (such as the one you already know related to allocator rebinding), but may not know why someone who developed ROS auto-generated tools used this construct.Katsuyama
@DanielLangr pre-C++11 platform dominate post-C++11 ones if not market-wise, but cost-wise and in absolute number of units functioning, the project involving usually supposes Very Long Life-Time. Even some "consumer" class platforms like Arduino began support C++11 partially only in recent time. Some modern aircraft may contain 100-200 single boards,controllers and embedded computer units and no-C++11 is allowed there :P ROS is an example of system designed for particular applications.Rung
D
6

std::allocator<void> is an allocator type that is used exclusively to declare other allocator types for specific objects via rebind template.

In your case Header typedef basically just says that default allocator for Header_ is std::allocator. Header_ uses it to create std::allocator<char> for frame_id. I guess style-wise it might as well be std::allocator<char> in first place (at the typedef) because Header_ at this point uses it for std::string only but Header_ doesn't look like plain container of char like std::string or std::vector so explicit sort of generic std::allocator<void> makes more sense. And probability what is more important in this case is that it is easier to use such allocator in script or template that auto-generates code.

For more information check:

Dupaix answered 12/4, 2021 at 9:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.