Search code examples
c++stlcontainerslanguage-lawyerallocator

mismatched std::allocator for some of STL containers


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.


Solution

  • 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.)