C++ 向量';什么是数据对齐?

C++ 向量';什么是数据对齐?,c++,vector,sse,memory-alignment,allocator,C++,Vector,Sse,Memory Alignment,Allocator,如果我想用SSE处理std::vector中的数据,我需要16字节对齐。我怎样才能做到这一点?我是否需要编写自己的分配器?或者默认分配器是否已经与16字节边界对齐?不要假设任何关于STL容器的内容。它们的界面/行为是定义的,但不是它们背后的内容。如果您需要原始访问,您必须按照您想要的规则编写自己的实现。标准要求new和new[]返回与任何数据类型对齐的数据,其中应包括SSE。MSVC是否真正遵循该规则是另一个问题。C++标准要求分配函数(malloc()和operator new())为任何标准

如果我想用SSE处理std::vector中的数据,我需要16字节对齐。我怎样才能做到这一点?我是否需要编写自己的分配器?或者默认分配器是否已经与16字节边界对齐?

不要假设任何关于STL容器的内容。它们的界面/行为是定义的,但不是它们背后的内容。如果您需要原始访问,您必须按照您想要的规则编写自己的实现。

标准要求
new
new[]
返回与任何数据类型对齐的数据,其中应包括SSE。MSVC是否真正遵循该规则是另一个问题。

C++标准要求分配函数(
malloc()
operator new()
)为任何标准类型分配适当对齐的内存。由于这些函数不接受对齐要求作为参数,在实践中,这意味着所有分配的对齐是相同的,并且是具有最大对齐要求的标准类型的对齐,通常是
long double
和/或
long
(请参阅)

向量指令,如SSE和AVX,具有比标准C++分配函数提供的更强的对齐要求(16位对齐128位访问和32位对齐256位访问)。code>posix_memalign()或

memalign()
可用于满足具有更强对齐要求的此类分配


在C++17中,接受类型为的附加参数

您可以像这样使用它:

#include <immintrin.h>
#include <memory>
#include <new>

int main() {
    std::unique_ptr<__m256i[]> arr{new(std::align_val_t{alignof(__m256i)}) __m256i[32]};
}
#包括
#包括
#包括
int main(){
std::unique_ptr arr{new(std::align_val_t{alignof(uu m256i)})uu m256i[32]};
}
此外,在C++17中,标准分配器已更新为尊重类型的对齐方式,因此您只需执行以下操作:

#include <immintrin.h>
#include <vector>

int main() {
    std::vector<__m256i> arr2(32);
}
#包括
#包括
int main(){
std::载体arr2(32);
}
或者(C++11中不涉及和支持堆分配):

#包括
#包括
int main(){
阵列arr3;
}

编写自己的分配器<代码>分配和
解除分配
是重要的两个方面。以下是一个例子:

pointer allocate( size_type size, const void * pBuff = 0 )
{
    char * p;

    int difference;

    if( size > ( INT_MAX - 16 ) )
        return NULL;

    p = (char*)malloc( size + 16 );

    if( !p )
        return NULL;

    difference = ( (-(int)p - 1 ) & 15 ) + 1;

    p += difference;
    p[ -1 ] = (char)difference;

    return (T*)p;
}

void deallocate( pointer p, size_type num )
{
    char * pBuffer = (char*)p;

    free( (void*)(((char*)p) - pBuffer[ -1 ] ) );
}
简短答复: 如果
sizeof(T)*vector.size()>16
则为是。
假设向量使用普通分配器

警告:只要
alignof(std::max\u align\u t)>=16
,因为这是最大对齐

长答覆: 更新日期:2017年8月25日新标准

如果对大于16的任何对象进行了对齐,则对16也进行了正确对齐

6.11对准(第4/5段) 路线表示为std::size\u t类型的值。有效的对齐仅包括基本类型的alignof表达式返回的值加上附加的实现定义的值集,该值集可能为空。每个校准值应为2的非负整数幂

路线的顺序为从弱到强或更严格的路线。更严格的路线具有更大的路线值。满足对齐要求的地址也满足任何较弱的有效对齐要求

new和new[]返回对齐的值,以便对象的大小正确对齐:

8.3.4新增(第17段) [注意:当分配函数返回的值不是null时,它必须是一个指向已为对象保留空间的存储块的指针。假定该存储块已正确对齐并具有请求的大小。如果object是一个数组。-结束注释]

注意:大多数系统都有最大对齐。动态分配的内存不需要对齐到大于此值的值

6.11校准(第2段) 基本路线由小于或等于所支持的最大路线的路线表示 通过在所有上下文中的实现,这等于alignof(std::max_align_t)(21.2) 当类型用作完整对象的类型和用作 子对象的类型


因此,只要分配的向量内存大于16字节,它就会在16字节边界上正确对齐。

您应该使用带有
std::
容器的自定义分配器,例如
vector
。不记得是谁编写了下面的一个,但我使用了一段时间,它似乎可以工作(您可能必须将
\u aligned\u malloc
更改为
\u mm\u malloc
,具体取决于编译器/平台):

我们几乎完成了!如果您使用Visual C++(至少是2010版),您将无法对指定对齐方式的类使用
std::vector
,因为
std::vector::resize

编译时,如果出现以下错误:

C:\Program Files\Microsoft Visual Studio 10.0\VC\include\vector(870):
error C2719: '_Val': formal parameter with __declspec(align('16')) won't be aligned
你必须破解你的
stl::vector头文件:

  • 找到
    向量
    头文件[C:\Program Files\Microsoft Visual Studio 10.0\VC\include\vector]
  • 找到
    void resize(_Ty_Val)
    方法[VC2010上的第870行]
  • 将其更改为
    void resize(const\u Ty&\u Val)

  • 使用
    declspec(align(x,y))
    如英特尔矢量化教程中所述,

    而不是编写自己的分配器,因为您可以像这样用于
    std::vector

    #include <vector>
    #include <boost/align/aligned_allocator.hpp>
    
    template <typename T>
    using aligned_vector = std::vector<T, boost::alignment::aligned_allocator<T, 16>>;
    
    #包括
    #包括
    模板
    使用对齐的_vector=std::vector;
    
    在C++11中,有一个
    对齐的\u存储
    。可能还有一个
    对齐的\u分配器
    ?让我检查一下。可能是重复的,看看@Fred在哪里提到了MSVC?“应该包括SSE”-但通常不会。上一次我检查时,Windows和Linux都只保证分配内存的8对齐,MSVC和glibc都没有采取任何措施来增加对齐。我相信黄鼠狼的说法是不正确的
    std::vector<T, AlignmentAllocator<T, 16> > bla;
    
    class __attribute__ ((aligned (16))) Foo {
        __attribute__ ((aligned (16))) double u[2];
    };
    
    C:\Program Files\Microsoft Visual Studio 10.0\VC\include\vector(870):
    error C2719: '_Val': formal parameter with __declspec(align('16')) won't be aligned
    
    #include <vector>
    #include <boost/align/aligned_allocator.hpp>
    
    template <typename T>
    using aligned_vector = std::vector<T, boost::alignment::aligned_allocator<T, 16>>;