What is the recommended way to align memory in C++11
Unfortunately the best I have found is allocating extra space and then using the "aligned" part. So the RingBuffer new
can request an extra 64 bytes and then return the first 64 byte aligned part of that. It wastes space but will give the alignment you need. You will likely need to set the memory before what is returned to the actual alloc address to unallocate it.
[Memory returned][ptr to start of memory][aligned memory][extra memory]
(assuming no inheritence from RingBuffer) something like:
void * RingBuffer::operator new(size_t request)
{
static const size_t ptr_alloc = sizeof(void *);
static const size_t align_size = 64;
static const size_t request_size = sizeof(RingBuffer)+align_size;
static const size_t needed = ptr_alloc+request_size;
void * alloc = ::operator new(needed);
void *ptr = std::align(align_size, sizeof(RingBuffer),
alloc+ptr_alloc, request_size);
((void **)ptr)[-1] = alloc; // save for delete calls to use
return ptr;
}
void RingBuffer::operator delete(void * ptr)
{
if (ptr) // 0 is valid, but a noop, so prevent passing negative memory
{
void * alloc = ((void **)ptr)[-1];
::operator delete (alloc);
}
}
For the second requirement of having a data member of RingBuffer
also 64 byte aligned, for that if you know that the start of this
is aligned, you can pad to force the alignment for data members.
The answer to your problem is std::aligned_storage. It can be used top level and for individual members of a class.
After some more research my thoughts are:
Like @TemplateRex pointed out there does not seem to be a standard way to align to more than 16 bytes. So even if we use the standardized
alignas(..)
there is no guarantee unless the alignment boundary is less than or equal to 16 bytes. I'll have to verify that it works as expected on a target platform.__attribute ((aligned(#)))
oralignas(..)
cannot be used to align a heap allocated object as I suspected i.e.new()
doesn't do anything with these annotations. They seem to work for static objects or stack allocations with the caveats from (1).Either
posix_memalign(..)
(non standard) oraligned_alloc(..)
(standardized but couldn't get it to work on GCC 4.8.1) + placementnew(..)
seems to be the solution. My solution for when I need platform independent code is compiler specific macros :)Alignment for struct/class fields seems to work with both
__attribute ((aligned(#)))
andalignas()
as noted in the answer. Again I think the caveats from (1) about guarantees on alignment stand.
So my current solution is to use posix_memalign(..)
+ placement new(..)
for aligning a heap allocated instance of my class since my target platform right now is Linux only. I am also using alignas(..)
for aligning fields since it's standardized and at least works on Clang and GCC. I'll be happy to change it if a better answer comes along.