Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why the requirement for custom allocators to be copyconstructible?

Tags:

c++

c++11

The C++11 standard (or at least, this working draft) requires that classes which implement the Allocator concept provide copy constructors.

This made sense back when all allocators had to be stateless, but when state is allowed in an allocator class, providing a copy constructor might not be desirable. For example, if the allocator implements some kind of slab allocation system or memory pool, where it maintains an internal freelist. It seems to me that such an allocator should always be moved, never copied. Actually copying it would require allocating new storage and then completely reproducing the internal state of the original allocator, including all free memory blocks, free-lists, etc. (Or does "copying" an Allocator simply imply returning Allocator(), i.e. returning a new default-constructed allocator?)

Actually copying a state-ful allocator seems to be totally unnecessary because as far as I can see, in practice there's no real common use-case for copy-constructing an allocator. No Container actually copies an allocator - C++11 containers will call Allocator::select_on_container_copy_construction within the container copy constructor instead, which usually just returns Allocator(). Then the container will usually just copy element by element from the other container, probably by just calling Container::insert.

Of course an optimized container implementation might do something more complex using internal knowledge about the container structure, but still nobody is going to copy-construct other.get_allocator() - the Container will just call other.get_allocator().select_on_container_copy_construction() to get a default-constructed allocator.

So why do we have the requirement that an Allocator itself must be copy-constructible? Shouldn't move construction be sufficient?


Note: To be clear, this question is not a duplicate of why does allocator in c++ need a copy constructor?. That question is asking specifically about std::allocator (which is stateless), whereas I am asking about custom allocators that implement the Allocator concept.

like image 493
Siler Avatar asked Dec 13 '14 18:12

Siler


1 Answers

Re the claim

No Container actually copies an allocator

that may be so (I haven't tested), and std::string may be regarded as a non-Container, but still:

#include <string>
#include <iostream>
#include <memory>       // std::allocator

template< class Type >
struct Alloc
    : std::allocator<Type>
{
    using Base = std::allocator<Type>;

    template< class Other > 
    struct rebind
    { 
        using other = Alloc<Other>;
    };

    Alloc() {}

    Alloc( Alloc<Type> const& other )
        : Base( other )
    { std::clog << "Alloc::<copy>\n"; }

    template<class Other> 
    Alloc( Alloc<Other> const& other )
        : Base( other )
    { std::clog << "Alloc::<generic-copy>\n"; }
};

auto main() -> int
{
    using namespace std;
    basic_string< char, char_traits<char>, Alloc<char> > a = "A", b = "B";
    a = b;
}

Output with Visual C++:

Alloc::<copy>
Alloc::<copy>

With g++ the number of allocator copy operations is higher.

like image 131
Cheers and hth. - Alf Avatar answered Nov 16 '22 02:11

Cheers and hth. - Alf