2012-10-17 77 views
38

是否有可能讓std::vector的自定義結構分配對齊內存以便進一步處理SIMD指令?如果可以使用Allocator,有沒有人碰巧擁有這樣一個分配器,他可以分享?讓std :: vector分配對齊的內存

+1

的文檔是否檢查過標準分配器是否已經爲您做了這些工作? – TemplateRex

+2

@rhalbersma:我不這麼認爲,它不需要對齊參數。 –

+0

沒有我的意思是:你的STL實現是否已經爲你調整了內存?你是否計算過'v.begin()'的內存地址並檢查它是否以X字節的倍數開始?即使你不能明確配置對齊方式,std :: allocator可能已經幫你完成了。 – TemplateRex

回答

26

編輯:我按照GManNickG的建議去除了std::allocator的繼承,並將alignment參數設置爲編譯時間的東西。

我最近寫了這段代碼。它沒有像我想要的那樣測試,所以繼續並報告錯誤。 :-)

enum class Alignment : size_t 
{ 
    Normal = sizeof(void*), 
    SSE = 16, 
    AVX = 32, 
}; 


namespace detail { 
    void* allocate_aligned_memory(size_t align, size_t size); 
    void deallocate_aligned_memory(void* ptr) noexcept; 
} 


template <typename T, Alignment Align = Alignment::AVX> 
class AlignedAllocator; 


template <Alignment Align> 
class AlignedAllocator<void, Align> 
{ 
public: 
    typedef void*    pointer; 
    typedef const void*  const_pointer; 
    typedef void    value_type; 

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


template <typename T, Alignment Align> 
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; 

    typedef std::true_type propagate_on_container_move_assignment; 

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

public: 
    AlignedAllocator() noexcept 
    {} 

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

    size_type 
    max_size() const noexcept 
    { return (size_type(~0) - size_type(Align))/sizeof(T); } 

    pointer 
    address(reference x) const noexcept 
    { return std::addressof(x); } 

    const_pointer 
    address(const_reference x) const noexcept 
    { return std::addressof(x); } 

    pointer 
    allocate(size_type n, typename AlignedAllocator<void, Align>::const_pointer = 0) 
    { 
     const size_type alignment = static_cast<size_type>(Align); 
     void* ptr = detail::allocate_aligned_memory(alignment , n * sizeof(T)); 
     if (ptr == nullptr) { 
      throw std::bad_alloc(); 
     } 

     return reinterpret_cast<pointer>(ptr); 
    } 

    void 
    deallocate(pointer p, size_type) noexcept 
    { return detail::deallocate_aligned_memory(p); } 

    template <class U, class ...Args> 
    void 
    construct(U* p, Args&&... args) 
    { ::new(reinterpret_cast<void*>(p)) U(std::forward<Args>(args)...); } 

    void 
    destroy(pointer p) 
    { p->~T(); } 
}; 


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

    typedef std::true_type propagate_on_container_move_assignment; 

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

public: 
    AlignedAllocator() noexcept 
    {} 

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

    size_type 
    max_size() const noexcept 
    { return (size_type(~0) - size_type(Align))/sizeof(T); } 

    const_pointer 
    address(const_reference x) const noexcept 
    { return std::addressof(x); } 

    pointer 
    allocate(size_type n, typename AlignedAllocator<void, Align>::const_pointer = 0) 
    { 
     const size_type alignment = static_cast<size_type>(Align); 
     void* ptr = detail::allocate_aligned_memory(alignment , n * sizeof(T)); 
     if (ptr == nullptr) { 
      throw std::bad_alloc(); 
     } 

     return reinterpret_cast<pointer>(ptr); 
    } 

    void 
    deallocate(pointer p, size_type) noexcept 
    { return detail::deallocate_aligned_memory(p); } 

    template <class U, class ...Args> 
    void 
    construct(U* p, Args&&... args) 
    { ::new(reinterpret_cast<void*>(p)) U(std::forward<Args>(args)...); } 

    void 
    destroy(pointer p) 
    { p->~T(); } 
}; 

template <typename T, Alignment TAlign, typename U, Alignment UAlign> 
inline 
bool 
operator== (const AlignedAllocator<T,TAlign>&, const AlignedAllocator<U, UAlign>&) noexcept 
{ return TAlign == UAlign; } 

template <typename T, Alignment TAlign, typename U, Alignment UAlign> 
inline 
bool 
operator!= (const AlignedAllocator<T,TAlign>&, const AlignedAllocator<U, UAlign>&) noexcept 
{ return TAlign != UAlign; } 

實際分配呼叫的實施只有posix,但您可以輕鬆擴展。

void* 
detail::allocate_aligned_memory(size_t align, size_t size) 
{ 
    assert(align >= sizeof(void*)); 
    assert(nail::is_power_of_two(align)); 

    if (size == 0) { 
     return nullptr; 
    } 

    void* ptr = nullptr; 
    int rc = posix_memalign(&ptr, align, size); 

    if (rc != 0) { 
     return nullptr; 
    } 

    return ptr; 
} 


void 
detail::deallocate_aligned_memory(void *ptr) noexcept 
{ 
    return free(ptr); 
} 

需要C++ 11,順便說一句。

+0

我不認爲你需要或應該從'std :: exception <>''std :: allocator <>'繼承。 – GManNickG

+0

@GManNickG,也許你的意思是'allocator'? :) – avakar

+0

@avakar:哇,甚至沒有注意到我寫的! – GManNickG

3

是的,應該是可以的。如果你把谷歌這個問題,那麼你將獲得大量的示例代碼,下面是一些令人鼓舞的結果:

https://bitbucket.org/marten/alignedallocator/wiki/Home

http://code.google.com/p/mastermind-strategy/source/browse/trunk/src/util/aligned_allocator.hpp?r=167

https://gist.github.com/1471329

+1

儘管此鏈接可能回答問題,但最好在此處包含答案的重要部分,並提供供參考的鏈接。如果鏈接頁面更改,則僅鏈接答案可能會失效。 - [發表評論](/ review/low-quality-posts/18787539) –

15

在即將到來的版本1.56,Boost庫將包括Boost.Align。在其他內存對齊幫助程序中,它提供boost::alignment::aligned_allocator,它可以用於std::allocator的直接替換,並允許您指定對齊方式。請參閱https://boostorg.github.io/align/

+0

很高興知道,但是我個人覺得'boost'很難融入我的項目(那些不是標題的庫)。 –

+3

我同意,整合提升可能有點痛苦。然而,'Boost.Align' _is_只有頭,也只依賴於其他僅頭的庫AFAICS。 – tklauser

+2

現已推出:http://www.boost.org/doc/libs/1_56_0/libs/core/doc/html/index.html – fireboot