What is the recommended way to align memory in C++11

前端 未结 4 575
难免孤独
难免孤独 2020-12-02 05:50

I am working on a single producer single consumer ring buffer implementation.I have two requirements:

  1. Align a single heap allocated instance of a ring buffer to
相关标签:
4条回答
  • 2020-12-02 06:09

    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.

    0 讨论(0)
  • 2020-12-02 06:10

    I don't know if it is the best way to align memory allocated with a new operator, but it is certainly very simple !

    This is the way it is done in thread sanitizer pass in GCC 6.1.0

    #define ALIGNED(x) __attribute__((aligned(x)))
    
    static char myarray[sizeof(myClass)] ALIGNED(64) ;
    var = new(myarray) myClass;
    

    Well, in sanitizer_common/sanitizer_internal_defs.h, it is also written

    // Please only use the ALIGNED macro before the type.
    // Using ALIGNED after the variable declaration is not portable!        
    

    So I do not know why the ALIGNED here is used after the variable declaration. But it is an other story.

    0 讨论(0)
  • 2020-12-02 06:18

    After some more research my thoughts are:

    1. 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.

    2. __attribute ((aligned(#))) or alignas(..) 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) or aligned_alloc(..) (standardized but couldn't get it to work on GCC 4.8.1) + placement new(..) seems to be the solution. My solution for when I need platform independent code is compiler specific macros :)

    3. Alignment for struct/class fields seems to work with both __attribute ((aligned(#))) and alignas() 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.

    0 讨论(0)
  • 2020-12-02 06:22

    The answer to your problem is std::aligned_storage. It can be used top level and for individual members of a class.

    0 讨论(0)
提交回复
热议问题