Oct 12, 2017

[C++] allocator template code

Reference:
https://howardhinnant.github.io/allocator_boilerplate.html
http://en.cppreference.com/w/cpp/container/vector/operator%3D
http://en.cppreference.com/w/cpp/memory/allocator_traits


C++11 and forward:

The commented out code represents functionality that std::allocator_traits<allocator<T>> defaults for us.

Notes:
  • is_always_equal is new for C++11 (hopefully that will be C++17).  It is now in C++17.
  • The default implementation for max_size() is not incredibly useful.
    Better if:
    return std::numeric_limits<size_type>::max() / sizeof(value_type);
    
  • Under discussion is the possibility to remove the requirement that you provide operator== and operator!= if is_always_equal{} is true.
  • The nested types reference and const_reference are no longer required in C++11 (as they were in C++03).
  • The member functions address(reference) and address(const_reference) are no longer required in C++11 (as they were in C++03).
  • Allocator must be CopyConstructible and MoveConstructible. If propagate_on_container_copy_assignment{} is true, 
  • allocator must be CopyAssignable if propagate_on_container_move_assignment{} is true, allocator must be MoveAssignable. 
  • If propagate_on_container_swap{} is true,  allocator must be Swappable. 
  • If they exist, these operations should not propagate an exception out. 
  • However they do not need to be marked with noexcept.
    Recommend marking them with noexcept if the compiler does not implicitly do so,
    so that traits such as is_nothrow_copy_constructible<allocator<T>> give the right answer.
  • If two allocators compare equal, that means that they can deallocate each other's allocated pointers. 
  • If two instances of your allocators can't do this, they must not compare equal to each other, else run time errors will result.
  • However copies, even converting copies, are required to compare equal.
template <class T>
class allocator
{
public:
    using value_type    = T;

//     using pointer       = value_type*;
//     using const_pointer = typename std::pointer_traits<pointer>::template
//                                                     rebind<value_type const>;
//     using void_pointer       = typename std::pointer_traits<pointer>::template
//                                                           rebind<void>;
//     using const_void_pointer = typename std::pointer_traits<pointer>::template
//                                                           rebind<const void>;

//     using difference_type = typename std::pointer_traits<pointer>::difference_type;
//     using size_type       = std::make_unsigned_t<difference_type>;

//     template <class U> struct rebind {typedef allocator<U> other;};

    allocator() noexcept {}  // not required, unless used
    template <class U> allocator(allocator<U> const&) noexcept {}

    value_type*  // Use pointer if pointer is not a value_type*
    allocate(std::size_t n)
    {
        return static_cast<value_type*>(::operator new (n*sizeof(value_type)));
    }

    void
    deallocate(value_type* p, std::size_t) noexcept  // Use pointer if pointer is not a value_type*
    {
        ::operator delete(p);
    }

//     value_type*
//     allocate(std::size_t n, const_void_pointer)
//     {
//         return allocate(n);
//     }

//     template <class U, class ...Args>
//     void
//     construct(U* p, Args&& ...args)
//     {
//         ::new(p) U(std::forward<Args>(args)...);
//     }

//     template <class U>
//     void
//     destroy(U* p) noexcept
//     {
//         p->~U();
//     }

//     std::size_t
//     max_size() const noexcept
//     {
//         return std::numeric_limits<size_type>::max();
//     }

//     allocator
//     select_on_container_copy_construction() const
//     {
//         return *this;
//     }

//     using propagate_on_container_copy_assignment = std::false_type;
//     using propagate_on_container_move_assignment = std::false_type;
//     using propagate_on_container_swap            = std::false_type;
//     using is_always_equal                        = std::is_empty<allocator>;
};

template <class T, class U>
bool
operator==(allocator<T> const&, allocator<U> const&) noexcept
{
    return true;
}

template <class T, class U>
bool
operator!=(allocator<T> const& x, allocator<U> const& y) noexcept
{
    return !(x == y);
}

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.