Unable to use custom allocator with allocate_shared/make_shared

前端 未结 2 828
离开以前
离开以前 2021-01-04 23:55

In my C++11 program, I use shared_ptr for some objects which are actively created and deleted. It so happened that standard allocator with operat

相关标签:
2条回答
  • 2021-01-05 00:23

    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>&);
    
    0 讨论(0)
  • 2021-01-05 00:34

    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.

    0 讨论(0)
提交回复
热议问题