How to force pointer returned by new operator to be 32-byte aligned

1.5k views Asked by At

I use AVX2 intrinsic in my program, and declare a __m256i variable in one of the class, like the following:

class A {
protected:
    __m256i buffer;
public:
    A() { 
        buffer = _mm256_setzero_si256();
    }
};

When I create an instance of A, if the memory location of buffer is not 32-byte aligned, I got a Seg Fault. Is there a way to force either the return address from new operator or the memory address of buffer to be 32-byte aligned?

3

There are 3 answers

1
jbapple On BEST ANSWER

I don't think you need placement new:

#include <cstdlib>
#include <new>

using size_t = ::std::size_t;

template <size_t ALIGNMENT>
struct alignas(ALIGNMENT) AlignedNew {
  static_assert(ALIGNMENT > 0, "ALIGNMENT must be positive");
  static_assert((ALIGNMENT & (ALIGNMENT - 1)) == 0,
      "ALIGNMENT must be a power of 2");
  static_assert((ALIGNMENT % sizeof(void*)) == 0,
      "ALIGNMENT must be a multiple of sizeof(void *)");
  static void* operator new(size_t count) { return Allocate(count); }
  static void* operator new[](size_t count) { return Allocate(count); }
  static void operator delete(void* ptr) { free(ptr); }
  static void operator delete[](void* ptr) { free(ptr); }

 private:
  static void* Allocate(size_t count) {
    void* result = nullptr;
    const auto alloc_failed = posix_memalign(&result, ALIGNMENT, count);
    if (alloc_failed)  throw ::std::bad_alloc();
    return result;
  }
};

Now simply inherit from AlignedNew<32>.

See also this proposal, which has been accepted for C++17: Dynamic memory allocation for over-aligned data.

6
alain On

You could try an alignment-specifier

class A {
protected:
    __m256i alignas(32) buffer;
    ...
};

See ยง7.6.2 of the C++ standard.

0
UnholySheep On

Based on the comments, as the alignas specifier seems not to work:

Most compilers have a built-in aligned allocation function, such as GCC's aligned_alloc. This function can be combined with the placement new operator to create aligned object instances.

For example:

void* ptr = aligned_alloc(32, sizeof(A));
A* a = new(ptr) A;

Note: using placement new requires a manual call of the destructor, using delete does not work