I would like to use C++11\'s std::aligned_alloc
, but unfortunately it isn\'t available with Microsoft Visual Studio 2013.
I\'m considering, intsead, im
Disclaimer: I didn't thoroughly test this code.
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));
}
Explanation:
The alignment is adjusted to alignof(void*)
if it's less than that, because, as we will see, we need to store a (properly aligned) void*
.
We need size + alignment - 1
bytes to ensure that we can find a size
byte block in there with the right alignment, plus an additional sizeof(void*)
bytes to store the pointer returned by ::operator new
so that we can free it later.
We allocate this memory with ::operator new
and store the returned pointer in allocated_mem
. We then add sizeof(void*)
bytes to allocated_mem
and store the result in aligned_mem
. At this point, we haven't aligned it yet.
At point #1, the memory block and the two points look like this:
aligned_mem (not actually aligned yet)
V
+-------------+-----------------------------------------+
|sizeof(void*)| size + alignment - 1 bytes |
+-------------+-----------------------------------------+
^
allocated_mem points here
The std::align
call adjusts aligned_mem
to obtain the desired alignment. At point #2, it now looks like this:
aligned_mem (correctly aligned now)
V
+---------------------+---------------------------------+
| extra space | at least size bytes |
+---------------------+---------------------------------+
^
allocated_mem points here
Because we started at sizeof(void*)
bytes past allocated_mem
, the "extra space" is at least sizeof(void*)
bytes. Moreover, aligned_mem
is correctly aligned for void*
, so we can store a void*
right before it. At point #3, the block of memory looks like this
aligned_mem (returned to caller)
V
+---------------+-----+---------------------------------+
| | ^ | at least size bytes |
+---------------+--+--+---------------------------------+
^ |
allocated_mem value of allocated_mem
points here stored here
As to aligned_free
, it simply reads the pointer stored there and passes it to ::operator delete
.
In Windows it's _aligned_malloc and _aligned_free, which can be found in malloc.h. The std implementation (of alignof/alignas) is in VS 2015. It's not available in 2013.