0

When I try to compile the code from this post (see below) in Visual Studio 2019, I receive the following compiler errors at line of the templated copy ctor:

Error   C2439   'PreAllocator<_Newfirst>::memory_ptr': member could not be initialized
Error   C2440   'initializing': cannot convert from 'T *const ' to 'T *'
Error   C2248   'PreAllocator<int>::memory_size': cannot access private member declared in class 'PreAllocator<int>'    
Error   C2248   'PreAllocator<int>::memory_ptr': cannot access private member declared in class 'PreAllocator<int>' 

Is this a compiler bug or am I missing something?


template <typename T>
class PreAllocator
{
private:
    T* memory_ptr;
    std::size_t memory_size;

public:
    typedef std::size_t     size_type;
    typedef T* pointer;
    typedef T               value_type;

    PreAllocator(T* memory_ptr, std::size_t memory_size) : memory_ptr(memory_ptr), memory_size(memory_size) {}

    PreAllocator(const PreAllocator& other) throw() : memory_ptr(other.memory_ptr), memory_size(other.memory_size) {};

    template<typename U>
    PreAllocator(const PreAllocator<U>& other) throw() : memory_ptr(other.memory_ptr), memory_size(other.memory_size) {};

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

    pointer allocate(size_type n, const void* hint = 0) { return memory_ptr; }
    void deallocate(T* ptr, size_type n) {}

    size_type max_size() const { return memory_size; }
};

int main()
{
    int my_arr[100] = { 0 };
    std::vector<int, PreAllocator<int>> my_vec(0, PreAllocator<int>(&my_arr[0], 100));
}
0xbadf00d
  • 17,405
  • 15
  • 67
  • 107

1 Answers1

1
template<typename U>
PreAllocator(const PreAllocator<U>& other) throw() : memory_ptr(other.memory_ptr), memory_size(other.memory_size) {};

This constructor attempts to initialize memory_ptr of type T* from other.memory_ptr of type U*, which is different from T* (because otherwise a copy constructor would have been called instead). The std::vector implementation apparently uses an internal type to instantiate the allocator to allocate the storage, and a pointer to that type cannot be implicitly converted to int*, which you expect.

You must either explicitly cast the pointer, or store void* internally, which then you would cast to T* in allocate member function.

template <typename T>
class PreAllocator
{
private:
    void* memory_ptr;

    ...

public:
    template<typename U>
    PreAllocator(const PreAllocator<U>& other) throw() :
        memory_ptr(other.memory_ptr), memory_size(other.memory_size) {}

    pointer allocate(size_type n, const void* hint = 0)
    {
        return static_cast< pointer >(memory_ptr);
    }

    ...
};

Further, in the very same constructor, you are accessing memory_ptr and memory_size members of PreAllocator<U>, which is a different and unrelated type from PreAllocator<T> (again, because T and U are different types). These members are private in that class, which gives you the access errors.

You could mitigate this by making those members public or adding public accessors for them, or by making all specializations of PreAllocator friends with a declaration like this:

template <typename T>
class PreAllocator
{
    template< typename U >
    friend class PreAllocator;

    ...
};
Andrey Semashev
  • 10,046
  • 1
  • 17
  • 27
  • Thank you for your answer. That's indeed the solution. However, maybe I'm missing something, but I think there is a serious issue with this allocator class. I've asked for that in a separate post: https://stackoverflow.com/q/65812813/547231. Maybe you can take a look. – 0xbadf00d Jan 20 '21 at 15:44