Unable to use custom allocator with allocate_shared/make_shared

房东的猫 提交于 2019-11-30 19:17:15

Like this.. You need it templated, you need the rebind and the types and the allocate and deallocate members. It is also nice to have the operators..

#include <memory>

template<typename T>
struct Allocator
{
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;
    typedef T value_type;

    template<typename U>
    struct rebind {typedef Allocator<U> other;};

    Allocator() throw() {};
    Allocator(const Allocator& other) throw() {};

    template<typename U>
    Allocator(const Allocator<U>& other) throw() {};

    template<typename U>
    Allocator& operator = (const Allocator<U>& other) { return *this; }
    Allocator<T>& operator = (const Allocator& other) { return *this; }
    ~Allocator() {}

    pointer allocate(size_type n, const void* hint = 0)
    {
        return static_cast<T*>(::operator new(n * sizeof(T)));
    }

    void deallocate(T* ptr, size_type n)
    {
        ::operator delete(ptr);
    }
};

template <typename T, typename U>
inline bool operator == (const Allocator<T>&, const Allocator<U>&)
{
    return true;
}

template <typename T, typename U>
inline bool operator != (const Allocator<T>& a, const Allocator<U>& b)
{
    return !(a == b);
}


int main()
{
    std::allocate_shared<int, Allocator<int>>(Allocator<int>(), 0);
}

At the very LEAST, an allocator could look like:

template<typename T>
struct Allocator
{
    typedef T value_type;

    Allocator() noexcept {};

    template<typename U>
    Allocator(const Allocator<U>& other) throw() {};

    T* allocate(std::size_t n, const void* hint = 0)
    {
        return static_cast<T*>(::operator new(n * sizeof(T)));
    }

    void deallocate(T* ptr, size_type n)
    {
        ::operator delete(ptr);
    }
};

template <typename T, typename U>
inline bool operator == (const Allocator<T>&, const Allocator<U>&)
{
    return true;
}

template <typename T, typename U>
inline bool operator != (const Allocator<T>& a, const Allocator<U>& b)
{
    return !(a == b);
}

This will also work for allocate_shared.. However, being the type of person I am, I prefer to have all the functions.. Even the ones not required/used by said container/function.

Your custom allocator does not meet the C++ Allocator requirements.

In particular, it does not support being rebound to allocate objects of a different type. Usually allocators are templates, parameterized on the type they allocate memory for. allocate_shared needs to rebind the allocator so it can allocate a block of memory of the appropriate size and type, it does not want to allocate an array of char objects.

// MyAlloc is a correct allocator, since allocator_traits can be instantiated

This is not a correct assumption. Instantiating allocator_traits<MyAlloc> does not instantiate all its members.

Also, is it OK to use char as value_type for this particular allocator

That makes your allocator an allocator of char, but allocate_shared needs an allocator of some_internal_type_defined_by_the_library and so it tries to use std::allocator_traits<MyAlloc>::rebind_alloc<some_internal_type_defined_by_the_library> to get an allocator for that type, but your allocator does not support the rebind requirement.

If your allocator is a template of the form MyAlloc<T> then allocator_traits can determine how to rebind it to MyAlloc<U>, otherwise the type MyAlloc::rebind<U>::other needs to be valid.

The C++ standard shows the following as an example of an allocator supporting the minimum requirements for a C++ Allocator type:


template <class Tp>
struct SimpleAllocator {
  typedef Tp value_type;
  SimpleAllocator(ctor args);
  template <class T> SimpleAllocator(const SimpleAllocator<T>& other);
  Tp* allocate(std::size_t n);
  void deallocate(Tp* p, std::size_t n);
};
template <class T, class U>
bool operator==(const SimpleAllocator<T>&, const SimpleAllocator<U>&);
template <class T, class U>
bool operator!=(const SimpleAllocator<T>&, const SimpleAllocator<U>&);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!