分配32字节对齐内存的分配器

时间:2014-10-03 13:01:21

标签: c++ allocator

下面的代码定义了一个自定义分配器,它分配32字节对齐的内存。

我使用Visual Studio 2010编译了代码。 代码在发布模式下编译良好。 在调试模式下,我得到一个编译错误,见下文,我不明白。 代码有什么问题?

#include <memory>
#include <vector>

inline void* aligned_malloc(size_t n)
{
    if(n == 0) return nullptr;
    char* p = (char*)malloc(n + 32);
    if(p == nullptr) return nullptr;
    size_t offset = 32 - (size_t)p % 32;
    p += offset;
    *(p - 1) = (char)offset;
    return p;
}

inline void aligned_free(void* p)
{
    if(p == nullptr) return;
    char offset = *((char*)p - 1);
    free((char*)p  - offset);
}

template<class T>
class AlignedAllocator {
public:
    typedef T value_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;

    T* address(T& x) const { return &x; }
    const T* address(const T& x) const { return &x; }

    size_t max_size() const { return (size_t)(-1) / sizeof(T); }

    T* allocate(size_t n, const T* = nullptr)
    {
        T* p = (T*)aligned_malloc(n * sizeof(T));
        if(!p) throw std::bad_alloc();
        return p;
    }
    void deallocate(pointer p, size_type) { aligned_free(p); }

    void construct(T* p, const T& x) { new(p) T(x); }
    void destroy(T* p) { p->~T(); }

    template<class U> struct rebind { typedef AlignedAllocator<U> other; };
};

std::vector<int, AlignedAllocator<int>> v;

调试模式下的编译错误:

c:\program files (x86)\microsoft visual studio 10.0\vc\include\vector(441): error C2440: 'initializing' : cannot convert from 'AlignedAllocator<T>' to 'AlignedAllocator<T>'
      with
      [
          T=int
      ]
      and
      [
          T=std::_Container_proxy
      ]
      No constructor could take the source type, or constructor overload resolution was ambiguous
      c:\program files (x86)\microsoft visual studio 10.0\vc\include\vector(437) : while compiling class template member function 'std::_Vector_val<_Ty,_Alloc>::_Vector_val(_Alloc)'
      with
      [
          _Ty=int,
          _Alloc=AlignedAllocator<int>
      ]
      c:\program files (x86)\microsoft visual studio 10.0\vc\include\vector(481) : see reference to class template instantiation 'std::_Vector_val<_Ty,_Alloc>' being compiled
      with
      [
          _Ty=int,
          _Alloc=AlignedAllocator<int>
      ]
      c:\users\rade\desktop 5\higg boson repository\tmp\tmp.cpp(52) : see reference to class template instantiation 'std::vector<_Ty,_Ax>' being compiled
      with
      [
          _Ty=int,
          _Ax=AlignedAllocator<int>
      ]

2 个答案:

答案 0 :(得分:3)

除其他外,分配器要求要求给定分配器类型X,任何类型U

using Y = typename X::template rebind<U>::other;

您可以从Y类型的对象构造X。 (适用于您的代码的缺点是您必须能够从AlignedAllocator<Foo>为任意类型AlignedAllocator<Bar>Foo构建Bar。)您的分配器不会不满足这个要求。在调试模式下,MSVC标准库重新绑定您的分配器以维护一些额外的内部数据以进行调试,而在发布模式下它不会这样做,这就是为什么您只看到编译器在调试模式下抱怨。

修复很简单 - 只需添加必要的构造函数:

AlignedAllocator() { }
template<class U> AlignedAllocator(const AlignedAllocator<U> &) { }

答案 1 :(得分:0)

这是代码的工作版本。它结合了我的问题中的代码,来自T.C.的答案。和一些额外的修复。我在这里发帖,以防有人觉得有用。

该代码已经过MSVS 2008和MSVS 2010的测试。它是用C ++ 98编写的。可能需要进行一些更改才能使其符合C ++ 11分配器要求。

#include <cstdlib>
#include <new>

inline void* alignedMalloc(size_t n)
{
    char* p = (char*)std::malloc(n + 32);
    if(!p) return 0;
    size_t offset = 32 - (size_t)p % 32;
    p += offset;
    *(p - 1) = (char)offset;
    return p;
}

inline void alignedFree(void* p)
{
    if(!p) return;
    char offset = *((char*)p - 1);
    std::free((char*)p  - offset);
}

template<class T>
class AlignedAllocator {
public:
    typedef T value_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;

    AlignedAllocator() {}
    template<class U> AlignedAllocator(const AlignedAllocator<U>&) {}

    T* address(T& x) const { return &x; }
    const T* address(const T& x) const { return &x; }

    size_t max_size() const { return (size_t)(-1) / sizeof(T); }

    T* allocate(size_t n, const T* = 0)
    {
        T* p = (T*)alignedMalloc(n * sizeof(T));
        if(!p) throw std::bad_alloc();
        return p;
    }

    void deallocate(T* p, size_t) { alignedFree(p); }

    void construct(T* p, const T& x) { new(p) T(x); }
    void destroy(T* p) { (void)p; p->~T(); }            // (void)p silences spurious MSVS 2010 compiler warning

    template<class U> struct rebind { typedef AlignedAllocator<U> other; };
};

template <class T>
bool operator==(const AlignedAllocator<T>&, const AlignedAllocator<T>&) { return true; }

template <class T>
bool operator!=(const AlignedAllocator<T>&, const AlignedAllocator<T>&) { return false; }