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

Allocator that allocates 32-byte aligned memory

本文关键字:分配器 内存 对齐 字节 分配      更新时间:2023-10-16

下面的代码定义了一个自定义分配器,用于分配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.0vcincludevector(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.0vcincludevector(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.0vcincludevector(481) : see reference to class template instantiation 'std::_Vector_val<_Ty,_Alloc>' being compiled
      with
      [
          _Ty=int,
          _Alloc=AlignedAllocator<int>
      ]
      c:usersradedesktop 5higg boson repositorytmptmp.cpp(52) : see reference to class template instantiation 'std::vector<_Ty,_Ax>' being compiled
      with
      [
          _Ty=int,
          _Ax=AlignedAllocator<int>
      ]

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

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

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

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

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

这里是代码的工作版本。它结合了我的问题、T.C.的答案和一些额外的修复程序中的代码。我把它贴在这里,以防有人发现它有用。

该代码已在MSVS2008和MSVS2010中进行了测试。它是用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; }