-1

I have the following toy code that works:

#include <cstdlib>
#include <vector>

template <typename T>
struct Dummy {
        using value_type = T;
        using size_type = size_t;
        using difference_type = ptrdiff_t;
        using pointer = value_type*;
        using const_pointer = const value_type*;
        using reference = value_type&;
        using const_reference = const value_type&;

        Dummy() = default;
        Dummy(const Dummy&) = default;
        
        pointer allocate(size_type n, const void* hint = 0) {
                (void)hint;
                return static_cast<pointer>(aligned_alloc(128, n * sizeof(T)));
        }

        void deallocate(void* p, size_type) {
                if (p)
                        free(p);
        }
};

int main()
{
        
        std::vector<int, Dummy<int, 16>> v;
        
        
        for (size_t i = 1; i < 5000; ++i)
                v.push_back(i);
        
        
        return 0;
}

Now I would like to templetize (not to put in the constructor) the alignment. I try to add to the template a integer parameter

template <typename T, size_t align>
struct Dummy {
        using value_type = T;
        using size_type = size_t;
        using difference_type = ptrdiff_t;
        using pointer = value_type*;
        using const_pointer = const value_type*;
        using reference = value_type&;
        using const_reference = const value_type&;

        Dummy() = default;
        Dummy(const Dummy&) = default;

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

        void deallocate(void* p, size_type) {
                if (p)
                        free(p);
        }
};

int main()
{
        
        std::vector<int, Dummy<int, 128>> v;
        
        
        for (size_t i = 1; i < 5000; ++i)
                v.push_back(i);
        
        
        return 0;
}

I'm getting a lot of compilation error both with g++ and clang++: for instance

/usr/include/c++/10.2.0/bits/alloc_traits.h:78:11: error: no type named 'type' in 'struct std::__allocator_traits_base::__rebind<Dummy<int, 128>, int, void>'
   78 |     using __alloc_rebind
      |           ^~~~~~~~~~~~~~
In file included from /usr/include/c++/10.2.0/vector:67,
                 from aligned.cpp:4:
/usr/include/c++/10.2.0/bits/stl_vector.h: In instantiation of 'class std::vector<int, Dummy<int, 128> >':
aligned.cpp:62:43:   required from here
/usr/include/c++/10.2.0/bits/stl_vector.h:474:20: error: '_M_allocate' has not been declared in 'std::_Base<int, Dummy<int, 128> >'
  474 |       using _Base::_M_allocate;
      |                    ^~~~~~~~~~~
/usr/include/c++/10.2.0/bits/stl_vector.h:475:20: error: '_M_deallocate' has not been declared in 'std::_Base<int, Dummy<int, 128> >'
  475 |       using _Base::_M_deallocate;

I do not understand what is going on. I notice that even if I do not use align in the class the compiler complaints the same way. If instead I put an unused typename inside the template everything is compiling fine. Can you help me?

MaPo
  • 613
  • 4
  • 9
  • 1
    allocator do not control alignment (it is impacted by it). C++17 has introduced keyword to control alignment of a class. Take a pick on that: https://stackoverflow.com/q/65826663/1387438 – Marek R Mar 31 '21 at 16:20
  • thanks for the information. What do you mean that the allocator does not control the alignment? Is my first example (the one without any problem) incorrect? However I have (alas!) to maintain some legacy code and I have to use only C++11, – MaPo Mar 31 '21 at 16:26
  • 1
    This is quite complex topic see this https://youtu.be/IAdLwUXRUvg?t=1266 and take a pick on my question (linked above). – Marek R Mar 31 '21 at 16:34
  • Ok, as far as I see by your reference there are some subtleties with placement new operator. I knew something about, and this was why I was trying to avoid it using the `cstdlib`. However what still surprises me is that my code do not even compile and I really cannot interpret the error messages.! – MaPo Mar 31 '21 at 16:41

1 Answers1

0

I think I found the way to fix the issue even though I'm not sure I fully understood all the details.

Thanks to: this and this I managed to write

template <typename T, size_t align>
struct Dummy {
        using value_type = T;
        using size_type = size_t;
        using difference_type = ptrdiff_t;
        using pointer = value_type*;
        using const_pointer = const value_type*;
        using reference = value_type&;
        using const_reference = const value_type&;

        template<class Other>
        struct rebind { using other =  Dummy<Other, align>; };



        
        Dummy() {};
        Dummy(const Dummy&) {};

        template <typename Other>
        Dummy(const Dummy<Other, align>&) {}
        
        pointer allocate(size_type n, const void* hint = 0) {
                (void)hint;
                return static_cast<pointer>(aligned_alloc(align, n * sizeof(T)));
        }

        void deallocate(void* p, size_type) {
                if (p)
                        free(p);
        }
};

which compiles and seems to have the correct behavior.

MaPo
  • 613
  • 4
  • 9