lppier February 2016

C++11 : Does new return contiguous memory?

float* tempBuf = new float[maxVoices]();

Will the above result in

1) memory that is 16-byte aligned?

2) memory that is confirmed to be contiguous?

What I want is the following:

float tempBuf[maxVoices] __attribute__ ((aligned));

but as heap memory, that will be effective for Apple Accelerate framework.

Thanks.

Answers


Bathsheba February 2016

If tempBuf is not nullptr then the C++ standard guarantees that tempBuf points to the zeroth element of least maxVoices contiguous floats.

(Don't forget to call delete[] tempBuf once you're done with it.)


MSalters February 2016

The memory will be aligned for float, but not necessarily for CPU-specific SIMD instructions. I strongly suspect on your system sizeof(float) < 16, though, which means it's not as aligned as you want. The memory will be contiguous: &A[i] == &A[0] + i.

If you need something more specific, new std::aligned_storage<Length, Alignment> will return a suitable region of memory, presuming of course that you did in fact pass a more specific alignment.

Another alternative is struct FourFloats alignas(16) {float[4] floats;}; - this may map more naturally to the framework. You'd now need to do new FourFloats[(maxVoices+3)/4].


Yam Marcovic February 2016

  1. It's guaranteed to be aligned properly with respect to the type you're allocating. So if it's an array of 4 floats (each supposedly 4 bytes), it's guaranteed to provide a usable sequence of floats. It's not guaranteed to be aligned to 16 bytes.
  2. Yes, it's guaranteed to be contiguous (otherwise what would be the meaning of a single pointer?)

If you want it to be aligned to some K bytes, you can do it manually with std::align. See MSalter's answer for a more efficient way of doing this.


Yakk February 2016

Yes, new returns contiguous memory.

As for alignment, no such alignment guarantee is provided. Try this:

template<class T, size_t A>
T* over_aligned(size_t N){
  static_assert(A <= alignof(std::max_align_t),
    "Over-alignment is implementation-defined."
  );
  static_assert( std::is_trivially_destructible<T>{},
    "Function does not store number of elements to destroy"
  );
  using Helper=std::aligned_storage_t<sizeof(T), A>;
  auto* ptr = new Helper[(N+sizeof(Helper)-1)/sizeof(Helper)];
  return new(ptr) T[N];
}

Use:

float* f = over_aligned<float,16>(37);

Makes an array of 37 floats, with the buffer aligned to 16 bytes. Or it fails to compile.

If the assert fails, it can still work. Test and consult your compiler documentation. Once convinced, put compiler-specific version guards around the static assert, so when you change compilers you can test all over again (yay).

If you want real portability, you have to have a fall back to std::align and manage resources separately from data pointers and count the number of T if and only if T has a non-trivial destructor, then store the number of T "before" the start of your buffer. It gets pretty silly.

Post Status

Asked in February 2016
Viewed 2,452 times
Voted 6
Answered 4 times

Search




Leave an answer