下面的代码定义了一个自定义分配器,它分配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>
]
答案 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; }