免责声明: 我并没有彻底测试这段代码。
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*));
std::align(alignment, size, aligned_mem, space);
*(static_cast<void**>(aligned_mem) - 1) = allocated_mem;
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
。
new
,它会调用构造函数。使用::operator new
来分配内存。返回一个void *
,不要对其进行模板化处理。 2)您需要分配额外的内存来存储由::operator new
返回的原始指针,以便稍后进行释放。 3)Windows 拥有_aligned_malloc
函数。 - T.C.void*
明确表示您正在返回已分配的存储空间,而不是构造对象。这些是应该分别处理的不同事物。 - T.C.std::aligned_storage
是你需要的。 - TNA::operator new
还是std::malloc
都会返回一个适用于任何数据类型的指针。 - user3810155