C++ 获得对齐内存的最佳跨平台方法

C++ 获得对齐内存的最佳跨平台方法,c++,c,performance,sse,memory-alignment,C++,C,Performance,Sse,Memory Alignment,下面是我通常用来与VisualStudio和GCC对齐内存的代码 inline void* aligned_malloc(size_t size, size_t align) { void *result; #ifdef _MSC_VER result = _aligned_malloc(size, align); #else if(posix_memalign(&result, align, size)) result = 0; #

下面是我通常用来与VisualStudio和GCC对齐内存的代码

inline void* aligned_malloc(size_t size, size_t align) {
    void *result;
    #ifdef _MSC_VER 
    result = _aligned_malloc(size, align);
    #else 
     if(posix_memalign(&result, align, size)) result = 0;
    #endif
    return result;
}

inline void aligned_free(void *ptr) {
    #ifdef _MSC_VER 
        _aligned_free(ptr);
    #else 
      free(ptr);
    #endif

}
这个代码一般可以吗?我还看到人们使用
\u-mm\u-malloc
\u-mm\u-free
。在大多数情况下,我需要对齐内存,它使用SSE/AVX。我可以一般使用这些函数吗?这将使我的代码简单得多

最后,很容易创建我自己的函数来对齐内存(见下文)。那么,为什么有这么多不同的通用函数来获得对齐内存(其中许多函数只在一个平台上工作)

此代码执行16字节对齐

float* array = (float*)malloc(SIZE*sizeof(float)+15);

// find the aligned position
// and use this pointer to read or write data into array
float* alignedArray = (float*)(((unsigned long)array + 15) & (~0x0F));

// dellocate memory original "array", NOT alignedArray
free(array);
array = alignedArray = 0;
见:和

编辑: 如果有人关心的话,我是从Eigen(Eigen/src/Core/util/Memory.h)中得到对齐的_malloc()函数的

编辑:
我刚刚发现MinGW的
posix_memalign
没有定义。但是,<>代码> MyMaMalc 对于Visual Studio 2012、GCC、MIWW和英特尔C++编译器都是有效的,因此它似乎是最方便的解决方案。它还需要使用自己的
\u mm\u free
函数,尽管在某些实现中,您可以将指针从
\u mm\u malloc
传递到标准
free
/
delete

您提出的第一个函数确实可以正常工作


您的“自制”功能也可以工作,但有一个缺点,即如果值已对齐,则只会浪费15个字节。有时可能并不重要,但操作系统很可能能够提供正确分配的内存,而不会产生任何浪费(如果需要将其对齐到256或4096字节,则添加“对齐-1”字节可能会浪费大量内存)

只要你可以调用一个特殊函数来进行释放,你的方法就可以了。不过,我会用另一种方法来处理您的
#ifdef
s:从指定的标准选项开始,然后回到特定于平台的选项。比如说

  • 如果
    \uuuuu STDC\u VERSION\uuuuu>=201112L
    使用
    对齐的\u alloc
  • 如果
    \u POSIX\u VERSION>=200112L
    使用
    POSIX\u memalign
  • 如果定义了
    \u MSC\u VER
    ,请使用Windows工具
  • 如果所有其他操作都失败,只需使用
    malloc
    /
    free
    并禁用SSE/AVX代码即可

  • 如果您希望能够将分配的指针传递到
    free
    ,问题就更难了;这在所有标准接口上都有效,但在Windows上无效,并且不一定与某些类unix系统的遗留
    memalign
    函数配合使用。

    如果编译器支持,C++11会添加一个
    std::align
    函数来进行运行时指针对齐。您可以像这样实现自己的malloc/free(未经测试):

    模板
    空*对齐的\u malloc(标准::大小\u t大小)
    {
    std::size\u t space=size+(Align-1);
    void*ptr=malloc(空间+sizeof(void*));
    作废*原件_ptr=ptr;
    char*ptr_字节=静态_转换(ptr);
    ptr_bytes+=sizeof(void*);
    ptr=静态_转换(ptr_字节);
    ptr=std::align(对齐、大小、ptr、空间);
    ptr_字节=静态_转换(ptr);
    ptr_字节-=sizeof(void*);
    std::memcpy(ptr_字节、原始ptr、sizeof(void*);
    返回ptr;
    }
    无空隙对齐(无空隙*ptr)
    {
    void*ptr_字节=静态_转换(ptr);
    ptr_字节-=sizeof(void*);
    作废*原件;
    std::memcpy(&original_ptr,ptr_字节,sizeof(void*));
    标准::免费(原件);
    }
    
    然后不必保留原始指针值来释放它。我不确定这是否是100%便携的,但如果不是,我希望有人会纠正我

    这是我的2美分:

    temp = new unsigned char*[num];
    AlignedBuffers = new unsigned char*[num];
    for (int i = 0; i<num; i++)
    {
        temp[i] = new  unsigned char[bufferSize +15];
        AlignedBuffers[i] = reinterpret_cast<unsigned char*>((reinterpret_cast<size_t>
                            (temp[i% num]) + 15) & ~15);// 16 bit alignment in preperation for SSE
    }
    
    temp=新的无符号字符*[num];
    AlignedBuffers=新的无符号字符*[num];
    
    对于(inti=0;i这里是一个固定的user2093113示例,直接代码不是为我生成的(void*未知大小)。我还将它放在一个模板类中,覆盖操作符new/delete,这样您就不必进行分配并调用placement new

    #include <memory>
    
    template<std::size_t Alignment>
    class Aligned
    {
    public:
        void* operator new(std::size_t size)
        {
            std::size_t space = size + (Alignment - 1);
            void *ptr = malloc(space + sizeof(void*));
            void *original_ptr = ptr;
    
            char *ptr_bytes = static_cast<char*>(ptr);
            ptr_bytes += sizeof(void*);
            ptr = static_cast<void*>(ptr_bytes);
    
            ptr = std::align(Alignment, size, ptr, space);
    
            ptr_bytes = static_cast<char*>(ptr);
            ptr_bytes -= sizeof(void*);
            std::memcpy(ptr_bytes, &original_ptr, sizeof(void*));
    
            return ptr;
        }
    
        void operator delete(void* ptr)
        {
            char *ptr_bytes = static_cast<char*>(ptr);
            ptr_bytes -= sizeof(void*);
    
            void *original_ptr;
            std::memcpy(&original_ptr, ptr_bytes, sizeof(void*));
    
            std::free(original_ptr);
        }
    };
    
    #包括
    模板
    类对齐
    {
    公众:
    void*运算符新(标准::大小\u t大小)
    {
    std::size\u t space=size+(对齐-1);
    void*ptr=malloc(空间+sizeof(void*));
    作废*原件_ptr=ptr;
    char*ptr_字节=静态_转换(ptr);
    ptr_bytes+=sizeof(void*);
    ptr=静态_转换(ptr_字节);
    ptr=标准::对齐(对齐、大小、ptr、空间);
    ptr_字节=静态_转换(ptr);
    ptr_字节-=sizeof(void*);
    std::memcpy(ptr_字节和原始ptr,sizeof(void*);
    返回ptr;
    }
    void操作符删除(void*ptr)
    {
    char*ptr_字节=静态_转换(ptr);
    ptr_字节-=sizeof(void*);
    作废*原件;
    std::memcpy(&original_ptr,ptr_字节,sizeof(void*));
    标准::免费(原件);
    }
    };
    
    像这样使用它:

    class Camera : public Aligned<16>
    {
    };
    
    class摄像头:公共对齐
    {
    };
    

    还没有测试这段代码的跨平台性。

    但是关于_mm_malloc呢?如果我使用SSE/AVX,通常使用它可以吗?因此,即使我没有使用SSE/AVX,为什么不使用它呢?如果编译器支持_mm_malloc(),那么这也是一个有效的解决方案。您需要使用
    _mm_free()
    也是。当然,您可以使用
    \u-mm\u-malloc()
    进行任何内存分配-但当然,小的分配会比“通常”浪费更多的空间。好的,我想我将开始使用_-mm\u-malloc()和_-mm\u-free()。至少在这样的情况下,当我需要对齐内存时,答案是正确的。这使代码简单得多。虽然地址的
    无符号long
    强制转换在实践中可能有效,但它可能无法在ILP32/LP64/LLP64(win64)之间移植数据模型。请参阅下面的“我的固定版本”。通过在void*上执行指针运算修复了编译器错误,并且对齐的\u malloc中的memcpy现在可以正确复制该值。即使对齐的分配器可用,此版本也总是浪费空间。-1.您可以通过使用一条语句简化
    delete
    if(ptr)std::free(static\u cast(ptr)[-1]);
    a
    
    
    class Camera : public Aligned<16>
    {
    };