免责声明:我没有彻底测试此代码。
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 中。然后我们将sizeof(void*) 字节添加到allocated_mem 并将结果存储在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
因为我们从sizeof(void*) 字节开始超过allocated_mem,所以“额外空间”至少是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。