Skip to content

Commit 1fc2d58

Browse files
hidmicivanpauno
andauthored
Keep custom allocator in publisher and subscription options alive. (#1647)
* Keep custom allocator in publisher and subscription options alive. Also, enforce an allocator bound to void is used to avoid surprises. Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com> * Avoid sizeof(void) in MyAllocator implementation. Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com> * Address peer review comment Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com> * Use a lazely initialized private field when 'allocator' is not initialized Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com> Co-authored-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
1 parent c15eb1e commit 1fc2d58

3 files changed

Lines changed: 35 additions & 12 deletions

File tree

rclcpp/include/rclcpp/publisher_options.hpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include <memory>
1919
#include <string>
20+
#include <type_traits>
2021
#include <vector>
2122

2223
#include "rcl/publisher.h"
@@ -64,6 +65,10 @@ struct PublisherOptionsBase
6465
template<typename Allocator>
6566
struct PublisherOptionsWithAllocator : public PublisherOptionsBase
6667
{
68+
static_assert(
69+
std::is_void_v<typename std::allocator_traits<Allocator>::value_type>,
70+
"Publisher allocator value type must be void");
71+
6772
/// Optional custom allocator.
6873
std::shared_ptr<Allocator> allocator = nullptr;
6974

@@ -80,10 +85,7 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
8085
to_rcl_publisher_options(const rclcpp::QoS & qos) const
8186
{
8287
rcl_publisher_options_t result = rcl_publisher_get_default_options();
83-
using AllocatorTraits = std::allocator_traits<Allocator>;
84-
using MessageAllocatorT = typename AllocatorTraits::template rebind_alloc<MessageT>;
85-
auto message_alloc = std::make_shared<MessageAllocatorT>(*this->get_allocator().get());
86-
result.allocator = rclcpp::allocator::get_rcl_allocator<MessageT>(*message_alloc);
88+
result.allocator = rclcpp::allocator::get_rcl_allocator<void>(*this->get_allocator());
8789
result.qos = qos.get_rmw_qos_profile();
8890
result.rmw_publisher_options.require_unique_network_flow_endpoints =
8991
this->require_unique_network_flow_endpoints;
@@ -102,10 +104,18 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
102104
get_allocator() const
103105
{
104106
if (!this->allocator) {
105-
return std::make_shared<Allocator>();
107+
if (!allocator_storage_) {
108+
allocator_storage_ = std::make_shared<Allocator>();
109+
}
110+
return allocator_storage_;
106111
}
107112
return this->allocator;
108113
}
114+
115+
private:
116+
// This is a temporal workaround, to make sure that get_allocator()
117+
// always returns a copy of the same allocator.
118+
mutable std::shared_ptr<Allocator> allocator_storage_;
109119
};
110120

111121
using PublisherOptions = PublisherOptionsWithAllocator<std::allocator<void>>;

rclcpp/include/rclcpp/subscription_options.hpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <chrono>
1919
#include <memory>
2020
#include <string>
21+
#include <type_traits>
2122
#include <vector>
2223

2324
#include "rclcpp/callback_group.hpp"
@@ -86,6 +87,10 @@ struct SubscriptionOptionsBase
8687
template<typename Allocator>
8788
struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
8889
{
90+
static_assert(
91+
std::is_void_v<typename std::allocator_traits<Allocator>::value_type>,
92+
"Subscription allocator value type must be void");
93+
8994
/// Optional custom allocator.
9095
std::shared_ptr<Allocator> allocator = nullptr;
9196

@@ -107,10 +112,7 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
107112
to_rcl_subscription_options(const rclcpp::QoS & qos) const
108113
{
109114
rcl_subscription_options_t result = rcl_subscription_get_default_options();
110-
using AllocatorTraits = std::allocator_traits<Allocator>;
111-
using MessageAllocatorT = typename AllocatorTraits::template rebind_alloc<MessageT>;
112-
auto message_alloc = std::make_shared<MessageAllocatorT>(*this->get_allocator().get());
113-
result.allocator = allocator::get_rcl_allocator<MessageT>(*message_alloc);
115+
result.allocator = allocator::get_rcl_allocator<void>(*this->get_allocator());
114116
result.qos = qos.get_rmw_qos_profile();
115117
result.rmw_subscription_options.ignore_local_publications = this->ignore_local_publications;
116118
result.rmw_subscription_options.require_unique_network_flow_endpoints =
@@ -124,15 +126,22 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
124126
return result;
125127
}
126128

127-
/// Get the allocator, creating one if needed.
128129
std::shared_ptr<Allocator>
129130
get_allocator() const
130131
{
131132
if (!this->allocator) {
132-
return std::make_shared<Allocator>();
133+
if (!allocator_storage_) {
134+
allocator_storage_ = std::make_shared<Allocator>();
135+
}
136+
return allocator_storage_;
133137
}
134138
return this->allocator;
135139
}
140+
141+
private:
142+
// This is a temporal workaround, to make sure that get_allocator()
143+
// always returns a copy of the same allocator.
144+
mutable std::shared_ptr<Allocator> allocator_storage_;
136145
};
137146

138147
using SubscriptionOptions = SubscriptionOptionsWithAllocator<std::allocator<void>>;

rclcpp/test/rclcpp/test_intra_process_manager_with_allocators.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <list>
1919
#include <memory>
2020
#include <string>
21+
#include <type_traits>
2122
#include <utility>
2223

2324
#include "test_msgs/msg/empty.hpp"
@@ -57,7 +58,10 @@ struct MyAllocator
5758
return nullptr;
5859
}
5960
num_allocs++;
60-
return static_cast<T *>(std::malloc(size * sizeof(T)));
61+
// Use sizeof(char) in place for sizeof(void)
62+
constexpr size_t value_size = sizeof(
63+
typename std::conditional<!std::is_void<T>::value, T, char>::type);
64+
return static_cast<T *>(std::malloc(size * value_size));
6165
}
6266

6367
void deallocate(T * ptr, size_t size)

0 commit comments

Comments
 (0)