custom allocator and std::map

74 views Asked by At

Here's the code i'm able to compile with gcc:

#include <iostream>
#include <map>

template <class T>
class map_alloc {
public:
    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 <class U>
    struct rebind {
        typedef map_alloc<U> other;
    };

    pointer allocate(size_type n, const void* hint = 0) {
        T* t = (T*) malloc ( n * sizeof(T) );
        return t;
    }

    void deallocate(pointer p, size_type n) {
        free ( p );
    }

};

typedef map_alloc<std::map<int, int>::value_type> alloctor;

int main() {
    std::map<int, int, std::less<int>, alloctor> dummy;
    (void)(dummy);
    return 0;
}

But attempt to compile with MSVC failed with quite weired error (attached below).

Tested with:

g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 msvc 2022 community, toolset v143.

Any ideas? Any example of custom memory allocator for std::map on MSVC?

Thank you.

Build started at 1:02...
1>------ Build started: Project: malloc_tester, Configuration: Debug x64 ------
1>alloc_tester.cpp
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27): error C2440: 'static_cast': cannot convert from 'map_alloc<U>' to 'map_alloc<U>'
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27): error C2440:         with
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27): error C2440:         [
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27): error C2440:             U=std::_Tree_node<std::pair<const int,int>,std::_Default_allocator_traits<std::allocator<std::pair<const int,int>>>::void_pointer>
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27): error C2440:         ]
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27): error C2440:         and
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27): error C2440:         [
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27): error C2440:             U=std::_Container_proxy
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27): error C2440:         ]
1>(compiling source file 'alloc_tester.cpp')
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27):
1>'map_alloc<U>::map_alloc': no overloaded function could convert all the argument types
1>        with
1>        [
1>            U=std::_Container_proxy
1>        ]
1>  C:\Temp\ConsoleApplication4\malloc_tester\alloc_tester.cpp(29,1):
1>  could be 'map_alloc<U>::map_alloc(map_alloc<U> &&)'
1>        with
1>        [
1>            U=std::_Container_proxy
1>        ]
1>      C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27):
1>      'map_alloc<U>::map_alloc(map_alloc<U> &&)': cannot convert argument 1 from 'map_alloc<U>' to 'map_alloc<U> &&'
1>        with
1>        [
1>            U=std::_Container_proxy
1>        ]
1>        and
1>        [
1>            U=std::_Tree_node<std::pair<const int,int>,std::_Default_allocator_traits<std::allocator<std::pair<const int,int>>>::void_pointer>
1>        ]
1>        and
1>        [
1>            U=std::_Container_proxy
1>        ]
1>          C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27):
1>          Reason: cannot convert from 'map_alloc<U>' to 'map_alloc<U>'
1>        with
1>        [
1>            U=std::_Tree_node<std::pair<const int,int>,std::_Default_allocator_traits<std::allocator<std::pair<const int,int>>>::void_pointer>
1>        ]
1>        and
1>        [
1>            U=std::_Container_proxy
1>        ]
1>          C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27):
1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>  C:\Temp\ConsoleApplication4\malloc_tester\alloc_tester.cpp(29,1):
1>  or       'map_alloc<U>::map_alloc(const map_alloc<U> &)'
1>        with
1>        [
1>            U=std::_Container_proxy
1>        ]
1>      C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27):
1>      'map_alloc<U>::map_alloc(const map_alloc<U> &)': cannot convert argument 1 from 'map_alloc<U>' to 'const map_alloc<U> &'
1>        with
1>        [
1>            U=std::_Container_proxy
1>        ]
1>        and
1>        [
1>            U=std::_Tree_node<std::pair<const int,int>,std::_Default_allocator_traits<std::allocator<std::pair<const int,int>>>::void_pointer>
1>        ]
1>        and
1>        [
1>            U=std::_Container_proxy
1>        ]
1>          C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27):
1>          Reason: cannot convert from 'map_alloc<U>' to 'const map_alloc<U>'
1>        with
1>        [
1>            U=std::_Tree_node<std::pair<const int,int>,std::_Default_allocator_traits<std::allocator<std::pair<const int,int>>>::void_pointer>
1>        ]
1>        and
1>        [
1>            U=std::_Container_proxy
1>        ]
1>          C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27):
1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>  C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27):
1>  while trying to match the argument list '(map_alloc<U>)'
1>        with
1>        [
1>            U=std::_Tree_node<std::pair<const int,int>,std::_Default_allocator_traits<std::allocator<std::pair<const int,int>>>::void_pointer>
1>        ]
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,27):
1>the template instantiation context (the oldest one first) is
1>  C:\Temp\ConsoleApplication4\malloc_tester\alloc_tester.cpp(34,50):
1>  see reference to class template instantiation 'std::map<int,int,std::less<int>,alloctor>' being compiled
1>  C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\map(72,20):
1>  see reference to class template instantiation 'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>' being compiled
1>        with
1>        [
1>            _Kty=int,
1>            _Ty=int,
1>            _Pr=std::less<int>,
1>            _Alloc=alloctor
1>        ]
1>  C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1071,6):
1>  while compiling class template member function 'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::~_Tree(void) noexcept'
1>        with
1>        [
1>            _Kty=int,
1>            _Ty=int,
1>            _Pr=std::less<int>,
1>            _Alloc=alloctor
1>        ]
1>      C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\map(369,1):
1>      see the first reference to 'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::~_Tree' in 'std::map<int,int,std::less<int>,alloctor>::~map'
1>        with
1>        [
1>            _Kty=int,
1>            _Ty=int,
1>            _Pr=std::less<int>,
1>            _Alloc=alloctor
1>        ]
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1075,25): error C2530: '_Alproxy': references must be initialized
1>(compiling source file 'alloc_tester.cpp')
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1076,32): error C3536: '_Alproxy': cannot be used before it is initialized
1>(compiling source file 'alloc_tester.cpp')
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1076,9): error C2672: '_Delete_plain_internal': no matching overloaded function found
1>(compiling source file 'alloc_tester.cpp')
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xmemory(1135,19):
1>could be 'void std::_Delete_plain_internal(_Alloc &,_Alloc::value_type *const ) noexcept'
1>  C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1076,9):
1>  Failed to specialize function template 'void std::_Delete_plain_internal(_Alloc &,_Alloc::value_type *const ) noexcept'
1>      C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1076,9):
1>      With the following template arguments:
1>          C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xtree(1076,9):
1>          '_Alloc=int'
1>Done building project "malloc_tester.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
========== Build completed at 1:02 and took 00,554 seconds ==========

Tested on different versions of MSVC. I'm not able to find operational example on the web.

I found one example here: https://github.com/moya-lang/Allocator/tree/master

The same issue, the same compiler's error.

2

There are 2 answers

0
waffentrager On

For some reason the msvc compiler cannot generate a template constructor for your class in debug mode, you can switch visual studio to release mode or add class constructor definitions

map_alloc() = default;

template<class A>
map_alloc(const map_alloc<A>&) noexcept {}
0
user12694877 On

Thank you, waffentrager.

Your answer is precise. MSVC makes me crazy. After of seveal hours of investigation I found almost the same solution you proposed.

#include <iostream>
#include <cassert>
#include <map>
#include <unordered_map>

template<typename T>
class Allocator : public std::allocator<T> {

public:
    Allocator() {
    }

    template<class Other>
    Allocator(const Allocator<Other>& _Right) {}

    inline typename std::allocator<T>::pointer allocate(typename std::allocator<T>::size_type n, typename std::allocator<void>::const_pointer = 0) {
        T* ret_val = nullptr;
        // custom allocator here...
        return ret_val;
    }

    inline void deallocate(typename std::allocator<T>::pointer p, typename std::allocator<T>::size_type n) {
        // custom delete here.
    }

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

};


int main() {

    int test_cnt = 5;

    {
        std::map<int, int, std::less<int>, Allocator< std::pair<const int, int> > > tester_map;
        for (int i(0); i < 100; ++i) {
            tester_map[i * i * i] = i;
        }
        tester_map.clear();
    }

    {
        std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Allocator< std::pair<const int, int> > > tester_unmap;
        for (int i(0); i < 100; ++i) {
            tester_unmap[i * i * i] = i;
        }
        tester_unmap.clear();
    }

    return 0;
}