是否可以使std::vector自定义结构分配对齐的内存以使用 SIMD 指令进行进一步处理?如果有可能,有Allocator没有人碰巧有这样一个他可以共享的分配器?
			
			26391 次
		
4 回答
            34        
        
		
编辑:我删除了std::allocatorGManNickG 建议的继承,并使对齐参数成为编译时的东西。
我最近写了这段代码。它没有像我希望的那样经过测试,所以继续并报告错误。:-)
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,顺便说一句。
于 2012-10-17T20:16:30.237   回答
    
    
            21        
        
		
在即将发布的 1.56 版本中,Boost 库将包含 Boost.Align。在它提供的其他内存对齐帮助器中boost::alignment::aligned_allocator,它可以用来替代std::allocator并允许您指定对齐方式。请参阅https://boostorg.github.io/align/上的文档
于 2014-06-23T08:11:49.647   回答
    
    
            4        
        
		
是的,这应该是可能的。如果你把这个问题放在谷歌上,那么你会得到很多示例代码,下面是一些有希望的结果:
于 2012-10-17T20:16:39.117   回答
    
    
            3        
        
		
从 C++17 开始,只需使用std::vector<__m256i>or 与任何其他对齐类型。有对齐的版本operator new,它被用于std::allocator对齐的类型(以及普通new的表达式,所以从 C++17 开始 new__m256i[N]也是安全的)。
@MarcGlisse 有一条评论说这个,使它成为一个答案,使其更加明显。
于 2021-09-11T12:46:03.943   回答