Does std::allocator_traits define rebind_alloc if rebind not present in custom allocator?
Asked Answered
P

2

8

I'm trying to rebind my custom allocator type, MyAllocator<foo>, for use in a basic_string class, e.g.:

std::basic_string<char, std::char_traits<char>, MyAllocator<char>> ...

The allocator is passed to the context as MyAllocator<void>, so I need to rebind the allocator.

From the cppreference page for std::allocator_traits, http://en.cppreference.com/w/cpp/memory/allocator_traits:

Member alias templates:

rebind_alloc<T>: Alloc::rebind<T>::other if present, otherwise Alloc<T, Args> if this Alloc is Alloc<U, Args>

My custom allocator implements allocator_traits, but does not define the rebind struct (which doesn't appear to be a requirement to implement allocator_traits). My understanding of the documentation is that it allocator_traits should understand rebind_alloc. However, if I try calling rebind_alloc on my custom allocator type:

template<typename T>
using RebindAlloc =
  typename std::allocator_traits<MyAllocator<void>>::template rebind_alloc<T>;

I get various compiler errors when I try to pass RebindAlloc<char> to the basic_string type:

In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/string:52:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/basic_string.h:114:41: error: 
  'rebind' following the 'template' keyword does not refer to a template
  typedef typename _Alloc::template rebind<_CharT>::other _CharT_alloc_type;

Clearly the documentation has misled me. Should I just give up on rebind_alloc and implement rebind in the custom allocator, or is there a correct way of doing this using allocator_traits?

I am using gcc 4.8 with C++11. 14 is not an option at the moment.

Here's a code snippet of what I'm trying to do: https://gist.github.com/jacquelinekay/0cee73d1d2d78d8edd31

Phosgene answered 21/10, 2015 at 17:1 Comment(8)
can you post a minimum (almost) compilable example that I can plug into my compiler to check?Stogner
I've edited it with a code snippet that should be valid, except for the compile error mentioned in the original post that I can't figure out.Phosgene
@Phosgene compiles fine starting from gcc 5.1Fluviatile
ah, thanks for checking that. So the documentation is correct, but 4.8 has an incomplete implementation of the standard, then?Phosgene
@Phosgene you can look up if there's any bug reported for stdlib not using allocator traits for operating on allocators. I'm not sure if the stdlib is forced to use them, I guess it is, but it was not implemented for std::basic_stringFluviatile
gcc.gnu.org/bugzilla/show_bug.cgi?id=56437Dwightdwindle
Thanks everyone for clarifying the problem. I'm in a situation where I can't change my compiler (working on a library targeting developers on gcc 4.8). I implemented a workaround for this particular issue, but now I'm running into the same bug trying to pass a custom allocator to std::shared_ptr. Anyone know a good workaround to make my allocator compatible with this interface?Phosgene
@Phosgene ask a new question with a minimal, complete, verifiable example, "I'm having a problem" isn't very descriptiveFluviatile
D
7

I am using gcc 4.8 with C++11.

Then you need to define rebind in your allocator, GCC's basic_string doesn't support the C++11 allocator requirements until version 5.1 (and then only for the new ABI string, i.e. std::__cxx::basic_string).

So your allocator must meet the C++03 Allocator requirements, defining all the members, because allocator_traits isn't used by string in 4.8

Dwightdwindle answered 21/10, 2015 at 18:58 Comment(0)
L
4

n3376 says in [allocator.traits.types]/10:

template <class T> using rebind_alloc = see below;

Alias template: Alloc::rebind<T>::other if such a type exists; otherwise, Alloc<T, Args> if Alloc is a class template instantiation of the form Alloc<U, Args>, where Args is zero or more type arguments; otherwise, the instantiation of rebind_alloc is ill-formed.

which agrees with cppreference. It (allocator traits) seem to have been added in C++11, so it does not appear in n1905. Further archaeology could detect where it arrived, but that isn't all that relevant.

It appears as if your compiler is not a compliant C++11 compiler in this regard.

With minor fixes, both gcc 5.2.0 and clang 3.7.0 in C++11 mode will compile your code without error.

It appears the only reasonable response, if you cannot change your compiler, is to implement a simple rebind.

Literary answered 21/10, 2015 at 18:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.