2014-10-03 77 views
1

下面的代碼定義了分配32字節對齊內存的自定義分配器。分配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> 
     ] 

回答

3

分配部要求,除其他事項外,要求給出一個allocator類型X,任何類型的U,並

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

你能夠從X類型的對象構建Y。 (它適用於您的代碼的不足之處在於,您必須能夠從AlignedAllocator<Bar>中爲任意類型構造AlignedAllocator<Foo>FooBar)。您的分配器不滿足該要求。在調試模式下,MSVC標準庫重新綁定您的分配器以維護一些額外的內部數據以用於調試目的,而在釋放模式下它不會執行此操作,這就是爲什麼您只能看到編譯器在調試模式下抱怨的原因。

的修復很簡單 - 只需要添加必要的構造函數:

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

非常感謝。這解決了問題。 – user763305 2014-10-03 13:17:15

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; }