1

I'd like to force a specific heap allocation to return an address that's 64-byte aligned, because that's a cache line boundary. I thought I could do it like this

int *p = new alignas(64) int;

but none of my compilers seem to give p an address that's a multiple of 64. Here's how I'm checking:

#include <iostream>

int main()
{
  int *p = new alignas(64) int;
  std::cout << long(p) % 64 << '\n';    // should print 0
}

I must be doing something wrong. But what?

KnowItAllWannabe
  • 12,972
  • 8
  • 50
  • 91
  • 1
    Two things: a) support for overaligned types is implementation dependent, and b) very pedantically, all you're checking is whether the *converted value* is divisible. As far as the language is concerned, you don't have a concept of "alignment of a pointer" other than through the new alignment language features. Pointers are not integers, they are only convertible to and from integers. – Kerrek SB Feb 19 '14 at 23:50
  • Note that I'm not checking the alignment of the pointer (that'd be the value of `&p`), I'm checking the alignment of what it points to. Yes, I agree, I'm checking the value of a pointer converted to a `long`, but is there a better way to see if my alignment request is being fulfilled? – KnowItAllWannabe Feb 19 '14 at 23:55
  • Yes, the new language features are pretty substantial and may have what you need, e.g. [`std::align`](http://en.cppreference.com/w/cpp/memory/align). Before C++11 there simply *wasn't* a standard notion of aligned memory, which is why it was added. You had to use platform-specific methods before. – Kerrek SB Feb 20 '14 at 00:16
  • @KeithThompson: I'm not printing it as a `long`, I'm doing arithmetic on it to see if it's a multiple of 64. – KnowItAllWannabe Feb 20 '14 at 05:43
  • 1
    I deleted my comment. But you should probably convert to `uintptr_t` (declared in ``) if it's available. There are implementations where `int*` is bigger than `long`. – Keith Thompson Feb 20 '14 at 05:45

2 Answers2

2

The allocator called by the new operator in order to allocate space is "assumed to return pointers to storage that is appropriately aligned for objects of any type with fundamental alignment" (§3.7.4.1/2; quote is from §5.3.4/11). alignas(64) is probably not a "fundamental alignment" for your compiler and environment, so the allocation function doesn't need to respect it.

Note that the allocation function is only passed the amount of space requested; it has no idea what alignment is being requested. Consequently, it cannot adjust its result to fit special needs.

The alignas type specifier is designed to work with static and automatic objects. With such objects, the requested alignment must be respected if it is fundamental, and in an ideal world the compiler would produce an error message if it cannot guarantee that an extended alignment would be respected. (I don't believe it's obliged to do so, though; both gcc and clang produce executables which segfault if a huge stack-alignment is requested.)

rici
  • 234,347
  • 28
  • 237
  • 341
  • I just tested that with g++ 4.8 and nothing gets aligned beyond 8 bytes (which is the standard memory alignment anyway). I therefore don't see the usefulness of that keyword! On x86, there are registers that require memory to be 128 bytes aligned (and also 64 as the OP used) but somehow this is totally useless for that purpose. Too bad. I even tried against a struct and a class, all end up misaligned. If it only works on a type that is already aligned properly, then it was not necessary to add to the language! – Alexis Wilke Feb 20 '14 at 04:28
  • @AlexisWilke: It's designed for stack-allocated (automatic) objects. (And even there, it's not guaranteed to work but it should provide a compile-time error if the compiler can't guarantee the alignment.) All objects allocated with `new` have the same alignment (at least, with the default allocation function). I tried it with gcc 4.8/linux and it worked fine with alignas(8192). – rici Feb 20 '14 at 04:56
  • Ah... that works. Too bad it doesn't do it with a new too. I guess we're still bound to the good old memalign() function. – Alexis Wilke Feb 20 '14 at 05:16
1

Ask for 64 more bytes than you need, then generate a cache aligned address within the allocated space. Taking care to free the whole allocated memory at the end.

Tim Bergel
  • 499
  • 3
  • 9
  • I know that there are other ways to do what I want to do (e.g., use `std::aligned_storage` or `std::align`), but I'd really like to understand why my use of `alignas` isn't working. – KnowItAllWannabe Feb 19 '14 at 23:51
  • alignas operates on straightforward variables, not on new – Tim Bergel Feb 19 '14 at 23:55
  • 2
    goodness I'm ignorant - std::aligned storage looks very nice & std::align does just what I suggested but more neatly – Tim Bergel Feb 19 '14 at 23:57
  • 1
    By the way, `std::aligned_storage` is just short-hand for `alignas` so it also won't work with `new`. `std::align` is what you want. – rici Feb 20 '14 at 05:25
  • Actually you only need `(alignment - 1)` bytes extra space. – Emily L. Jul 17 '15 at 10:18