C++ 使 std::vector 分配对齐的内存
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12942548/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Making std::vector allocate aligned memory
提问by Violet Giraffe
Is it possible to make std::vector
of custom structs allocate aligned memory for further processing with SIMD instructions? If it is possible to do with Allocator
, does anyone happen to have such an allocator he could share?
是否可以使用std::vector
自定义结构分配对齐的内存以使用 SIMD 指令进行进一步处理?如果可以与Allocator
,有没有人碰巧有这样一个他可以共享的分配器?
采纳答案by Florian
Edit:I removed the inheritance of std::allocator
as suggested by GManNickG and made the alignment parameter a compile time thing.
编辑:我删除了std::allocator
GManNickG 建议的继承,并使对齐参数成为编译时的事情。
I recently wrote this piece of code. It's not tested as much as I would like it so go on and report errors. :-)
我最近写了这段代码。它没有像我希望的那样经过测试,所以继续并报告错误。:-)
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; }
The implementation for the actual allocate calls is posix only but you can extent that easily.
实际分配调用的实现仅是 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);
}
Needs C++11, btw.
需要 C++11,顺便说一句。
回答by tklauser
In the upcoming version 1.56, the Boost library will include Boost.Align. Among other memory alignment helpers it provides boost::alignment::aligned_allocator
, which can be used a drop-in replacement for std::allocator
and allows you to specify an alignment. See the documentation on https://boostorg.github.io/align/
在即将发布的 1.56 版本中,Boost 库将包含 Boost.Align。在它提供的其他内存对齐助手中boost::alignment::aligned_allocator
,它可以用作替代品std::allocator
并允许您指定对齐方式。请参阅https://boostorg.github.io/align/上的文档
回答by marcinj
Yes, it should be possible. If you put this question on google then you will get lots of sample code, below is some promising results:
是的,应该可以。如果你把这个问题放在 google 上,你会得到很多示例代码,下面是一些有希望的结果:
https://bitbucket.org/marten/alignedallocator/wiki/Home
https://bitbucket.org/marten/alignedallocator/wiki/Home