Using custom allocator for AllocatorAwareContainer data members of a class
Asked Answered
H

1

1

Given a non-stateless custom allocator A (say, arena allocator, binded to some contiguous memory chunk of runtime-known size) and class S, containing a fileds of AllocatorAwareContainer types:

struct S
{
    A() = default;
    // another c-tors
    std::vector< T > v;
    std::shared_ptr< U > s;
};

I want to use A for a subset (or even for all) AllocatorAwareContainer fields of class S. It is clear, that I should to provide one another template parameter for class S and change types of all the interesting data members correspondingly as follows:

template< typename A = std::allocator< void > >
struct S
{
    // c-tors
    template< typename X >
    using allocator = typename std::allocator_traits< A >::template rebind< X >::other;
    std::vector< T, allocator< T > > v;
    std::shared_ptr< U, allocator< U > > s;
};

What are changes in present constructors and additional constructors (assume A is not DefaultConstructible and any other possible restrictions may holds) should I made?

Should I store allocator A in additional field of class S?

What is a general tips to use custom allocators for classes?

Hachman answered 5/10, 2015 at 9:47 Comment(0)
W
1

I'm used to using the containers from bsl which are allocator-aware and to creating allocator-aware classes. The primary difference to the standard containers and their allocator use is that bsl uses a pointer to the allocator base class (bslma::Allocator). This approach gets nicely rid of the std::rebind-dance which complicates matters in an area which is already relatively complicated. Otherwise, I think the concepts translate. I don't have experience using allocators with standard library containers.

There are two fundamental rules for the use of allocators which work well in practice:

  1. The allocator of an object does not change once constructed.
  2. Every allocator-aware type shall pass an allocator received as constructor argument to all allocator-aware members.

The second rule implies that constructors of classes need to take care of all their members. Where the member type is known it is fairly straight forward to determine whether an allocator is needed and how it is to be constructed. When the member type is generic in some form, i.e., it depends on a template argument in some form, it is generally not known whether an allocator is needed.

When it is unclear whether a member needs to receive an allocator the approach used when using bsl is to hold a wrapped member. More specifically, the members would hold a bslalg::ConstructorProxy<T> which would determine statically with T supports constructors taking allocators and appropriate passes an allocator or not.

Webfoot answered 5/10, 2015 at 11:9 Comment(3)
Would using std::scoped_allocator_adaptor make sense here?Auspex
@legends2k: that is quite possible. However, I haven't used allocators with standard containers so I don't know.Marvelous
@Auspex For std::scoped-allocator_adaptor there should be a plenty (partial) specializations of std::uses_allocator<T,A>.Hachman

© 2022 - 2024 — McMap. All rights reserved.