在MS Visual Studio 2013中,我可以使用什么替代std::aligned_alloc?

11

我希望使用C++11的std::aligned_alloc,但不幸的是在Microsoft Visual Studio 2013中不可用。

因此,我考虑自己实现aligned_alloc。一个实现应该长什么样呢?例如下面的代码无法编译,因为它不能将void*转换为void*&

 template<typename T>
 T* aligned_alloc( std::size_t size, std::size_t align )
 {
        T* ptr = new T[size + align];
        std::align(align, size, reinterpret_cast<void*>(ptr), align + size);
        return ptr;
 }

4
1)不要使用 new ,它会调用构造函数。使用 ::operator new 来分配内存。返回一个 void *,不要对其进行模板化处理。 2)您需要分配额外的内存来存储由 ::operator new 返回的原始指针,以便稍后进行释放。 3)Windows 拥有 _aligned_malloc 函数。 - T.C.
返回 void* 有什么好处? - user1235183
1
void* 明确表示您正在返回已分配的存储空间,而不是构造对象。这些是应该分别处理的不同事物。 - T.C.
也许 std::aligned_storage 是你需要的。 - TNA
1
无论是 ::operator new 还是 std::malloc 都会返回一个适用于任何数据类型的指针。 - user3810155
显示剩余2条评论
2个回答

11

免责声明: 我并没有彻底测试这段代码。

void* aligned_alloc(std::size_t size, std::size_t alignment){
    if(alignment < alignof(void*)) { 
        alignment = alignof(void*); 
    }
    std::size_t space = size + alignment - 1;
    void* allocated_mem = ::operator new(space + sizeof(void*));
    void* aligned_mem = static_cast<void*>(static_cast<char*>(allocated_mem) + sizeof(void*)); 
    ////////////// #1 ///////////////
    std::align(alignment, size, aligned_mem, space);
    ////////////// #2 ///////////////
    *(static_cast<void**>(aligned_mem) - 1) = allocated_mem;
    ////////////// #3 ///////////////
    return aligned_mem;
}

void aligned_free(void* p) noexcept {
    ::operator delete(*(static_cast<void**>(p) - 1));
}

解释:

如果对齐方式小于 alignof(void*),那么就将其调整为该值,因为我们需要存储一个(正确对齐的)void*

我们需要 size + alignment - 1 字节来确保我们可以在其中找到一个具有正确对齐方式的大小为 size 的块,再加上额外的 sizeof(void*) 字节来存储由 ::operator new 返回的指针,以便稍后可以释放它。

我们使用 ::operator new 来分配这段内存,并将返回的指针存储在 allocated_mem 中。然后,我们将 allocated_mem 加上 sizeof(void*) 字节,并将结果存储在 aligned_mem 中。此时,我们还没有对其进行对齐。

在 #1 点,内存块和两个指针的情况如下:

              aligned_mem (not actually aligned yet)
              V
+-------------+-----------------------------------------+
|sizeof(void*)|    size + alignment - 1  bytes          |
+-------------+-----------------------------------------+
^
allocated_mem points here

std::align 调用会调整 aligned_mem 以获取所需对齐方式。在第 2 步,它现在看起来像这样:

                      aligned_mem (correctly aligned now)
                      V
+---------------------+---------------------------------+
| extra space         |  at least size bytes            |
+---------------------+---------------------------------+
^
allocated_mem points here

因为我们从allocated_mem之后的sizeof(void*)字节开始,所以“额外空间”至少为sizeof(void*)字节。此外,aligned_mem对于void*是正确对齐的,因此我们可以在其前面存储一个void*。在第3点时,内存块看起来像这样:

                      aligned_mem (returned to caller)
                      V
+---------------+-----+---------------------------------+
|               |  ^  |  at least size bytes            |
+---------------+--+--+---------------------------------+
^                  |
allocated_mem      value of allocated_mem
points here        stored here

对于aligned_free而言,它只是读取存储在那里的指针,并将其传递给::operator delete


虽然我不确定为什么要这样做,因为这两个功能已经存在于Windows上。 - Robinson
aligned_alloc 会在其返回值所指向的内存块前面存储 ::operator new 返回的指针。接着,aligned_free 只需读取该指针并将其传递给 ::operator delete 即可。 - T.C.

9
在Windows中,它是_aligned_malloc_aligned_free,可以在malloc.h中找到。 alignof / alignas的std实现在VS 2015中。 在2013中不可用。

3
根据我的测试,似乎在VS 2017中仍未实现aligned_alloc或aligned_malloc。因此,即使在VS 2017中,您仍然需要使用如上所述的_aligned_malloc。 - rezeli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接