mismatched std::allocator for some of STL containers
Asked Answered
B

1

9

Is it technically valid to use mismatched std::allocator specialization (surely, except its specialization for void) as a template parameter for STL containers (not all of them, but enumerated below plus unordered_(multi)map/set)? Following code compiles fine.

#include <list>
#include <forward_list>
#include <deque>
#include <set>
#include <map>

int main()
{
    struct A { bool operator < (A) const { return true; } };
    struct B {};
    struct C {};
    std::list< A, std::allocator< C > > l;
    std::forward_list< A, std::allocator< C > > fl;
    std::deque< A, std::allocator< C > > d;
    std::set< A, std::less< A >, std::allocator< C > > s;
    std::multiset< A, std::less< A >, std::allocator< C > > ms;
    std::map< A, B, std::less< A >, std::allocator< C > > m;
    std::multimap< A, B, std::less< A >, std::allocator< C > > mm;
}

I believe this is due to allocator being immediately rebound to underlying node type without any relation to its source type.

Bondstone answered 11/3, 2017 at 14:1 Comment(1)
I'd say it could be undefined behavior, but I don't know (maybe the allocator is the same for the different types anyway)Effieeffigy
K
10

I'd say this is UB (at least in C++11) because specifying an allocator which has a different value_type from the value_type of the container violates the allocator-aware container requirements which means those instances do not conform to the general container requirements. Furthermore, I can't find anything in the C++11 standard that says that the allocator types are to be rebound from the type provided as template parameter.


 1. Section [container.requirements.general] tells us:

13) All of the containers defined in this Clause and in (21.4) except array meet the additional requirements of an allocator-aware container, as described in Table 99.

 2. The Allocator-aware container requirements says:

Requires: allocator_type::value_type is the same as X::value_type.

  1. Section [default.allocator] specifies

typedef T value_type;

as a member of the allocator template in namespace std.

 4. Section [multimap.overview] contains:

template <class Key, class T, class Compare = less<Key>,
    class Allocator = allocator<pair<const Key, T> > >
class multimap {
    [...]
    typedef Allocator allocator_type;
    [...]
 };

(With similar findings for the other containers.)

Kutenai answered 11/3, 2017 at 14:50 Comment(9)
Points 1 + 2 are sufficient.Bondstone
@orient: No because the typedef in point 4 could read something like typedef typename std::allocator_traits<Allocator>::template rebind_alloc<value_type> allocator_type; which would make the picture a little different.Kutenai
Additional info: libc++ catches this UB at compile-time with a static_assert.Ballon
Additional additional info: libstdc++ intentionally doesn't catch this because we support it as a conforming extension, but I've been meaning to add static assertions for strict modes when extensions are not wanted.Probably
@Pixelchemist, "I can't find anything in the C++11 standard that says that the allocator types are to be rebound" Even if it doesn't say so, they must be for most allocator-aware containers in the standard to work, all of them except basic_string and vector (even vector<bool> will rebind). That was clarified as a defect report: wg21.link/lwg2218Probably
@JonathanWakely : Why would you rebind an allocator which has the proper value_type?Kutenai
@Pixelchemist, I'm not sure I even understand your question. What is the proper value_type for std::list<T, A> to allocate its internal node types? It's certainly not A because that allocates memory for objects of type T. What is the proper value_type for std::deque<T, A> to allocate the table of pointers to its pages? It's not A. Maybe you should consider how an allocator with the proper value_type can ever be provided to those containers when (as you quoted!) the containers require that "allocator_type::value_type is the same as X::value_type." They must rebind.Probably
@JonathanWakely : Absolutely. I'm too much into thinking along the Tracks of vector.Kutenai
@Pixelchemist, I specifically said that basic_string and vector don't need to rebind :-) So "Why would you rebind an allocator which has the proper value_type?" You wouldn't. But usually it has the wrong value type, so you need to.Probably

© 2022 - 2024 — McMap. All rights reserved.