7

All the allocator-aware class templates in the STL have to be instantiated with an allocator type. Wouldn't it be a lot more convenient for users if the allocator wasn't a template argument but a template template argument?

To demonstrate, the std::vector and std::basic_string class templates have the following signatures respectively:

template<class T, class Allocator = std::allocator<T>> class vector;
template<class CharT, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT>> class basic_string;

If I have a custom allocator:

template <typename T>
class MyAllocator
{
    // ...
};

and want to instantiate a vector of strings that uses my custom allocator both to allocate internal storage for the vector and for the strings' internal character arrays, things quickly become awkward:

typedef std::vector<std::basic_string<char, std::char_traits<char>, MyAllocator<char> >, MyAllocator<std::basic_string<char, std::char_traits<char>, MyAllocator<char>>>> CustomAllocStringVector;

Using an additional typedef, this can be simplified somewhat:

typedef std::basic_string<char, std::char_traits<char>, MyAllocator<char>> CustomAllocString;
typedef std::vector<CustomAllocString, MyAllocator<CustomAllocString>> CustomAllocStringVector;

But the thing that bothers me is, why force the user to explicitly specify the full type of the allocator? If I'm using the allocator for a vector of char, shouldn't it go without saying that the allocator is going to be of type allocator< char >?

If the signatures of std::vector and std::basic_string were:

template<typename T, template <typename ElementType> class AllocatorType = std::allocator> class vector;
template<typename CharT, typename Traits = std::char_traits<CharT>, template <typename ElementType> class AllocatorType = std::allocator> class basic_string;

the same vector type as above could be more simply typedef'd as:

typedef std::basic_string<char, std::char_traits<char>, MyAllocator> CustomAllocString;
typedef std::vector<CustomAllocString, MyAllocator> CustomAllocStringVector;

My way, of course, would require that all allocators be templates, but wouldn't any allocator class that is supposed to be the least bit reusable have to meet this requirement anyway?

I'm sure there is a good reason for this, but at the moment I'm not seeing it.

antred
  • 3,697
  • 2
  • 29
  • 37
  • 1
    Actually, even as I was typing this question, another thing occurred to me. Why does an allocator have to care about about what type it is used for at all? Why can't client code just ask for x bytes with alignment y without ever mentioning any type names? That way, this whole issue would go away. – antred Aug 29 '14 at 16:23
  • 1
    What if you want the allocator's type to be templated on something in addition to (or instead of) the type contained in the container? – T.C. Aug 29 '14 at 16:26
  • The allocator's type does not have to be a specialization of a class template. You can restrict it to a single type, which might be useful for special-purpose allocators. – dyp Aug 29 '14 at 16:26
  • @T.C. I guess that's a knockout argument already. My way to impose a very specific template signature on all allocators and make any other template sigature impossible. :-\ Very good point. I knew there was going to be a good reason! – antred Aug 29 '14 at 16:28
  • @T.C. I think in C++11, you could use an alias template for that purpose. – dyp Aug 29 '14 at 16:28
  • @dyp Yes, but the standard library containers as we know and love and hate were designed in C++98 – T.C. Aug 29 '14 at 16:29
  • *"Why does an allocator have to care about about what type it is used for at all?"* - Are you not giving yourself the answer here? – Christian Hackl Aug 29 '14 at 16:34
  • @ Christian Hackl Yes, I realized a few minutes ago that my proposal was hogwash. :-) But still, the signatures of the allocate() method any allocator in C++ RIGHT NOW already demand that the method return a pointer of type T*. I'm wondering why that should be necessary. – antred Aug 29 '14 at 16:38
  • 1
    Here is a related question (pretty much a duplicate, actually) [Why is allocator::rebind necessary when we have template template parameters](http://stackoverflow.com/questions/12362363/why-is-allocatorrebind-necessary-when-we-have-template-template-parameters). – Mikael Persson Aug 29 '14 at 16:39
  • @T.C. IIRC, the allocator interface was re-designed for C++11. – dyp Aug 29 '14 at 16:57
  • @Mikael Persson Thanks for the link to the other discussion! Having read it, I'm now starting to realize that I have totally misdesigned the library I'm current working on. I thought I'd be smart about it and make the allocator in all my allocator-aware classes template template args, but after having read that one guy's comment where he stated that just because an allocator's allocate() and deallocate() methods mention T doesn't mean the allocator class itself has to (you can just templatize the methods but not the class), it's dawning on me that I've gone in the wrong direction. :-( – antred Aug 29 '14 at 16:57
  • 1
    @dyp They added `allocator_traits`, but the fundamental take-the-allocator-as-a-type-parameter design didn't and couldn't change. – T.C. Aug 29 '14 at 19:16

1 Answers1

4

This would introduce a requirement that the allocator type be a class template with exactly one template argument, specialized with the container's value_type. Your proposal would eliminate

template<typename T, unsigned int PoolNumber = 0>
class my_allocator;

as a valid allocator.

At the same time, I can simply use the typedef I already have for my allocator type, and don't need to take it apart or repeat its template name:

template<typename T> class my_allocator;

typedef my_allocator<int> int_allocator;

std::list<int, int_allocator> ...    // valid currently, difficult to express with your proposal
Simon Richter
  • 28,572
  • 1
  • 42
  • 64
  • 1
    `templateusing pool_3_allocator=my_allocator;` or `templatestruct pool_helper{templateusing allocator=my_allocator;};` handle that kind of corner case with a bit of extra verbage. I suspect the fact that the allocator interface is really old, and cannot be changed, is more important. – Yakk - Adam Nevraumont Aug 29 '14 at 20:11