1

In How use alignof to force alignment for a heap allocation?, I asked how to use alignof for heap-allocated objects. Now I'm generalizing my question for any way to force alignment of heap-allocated objects, because I can't find a way to do it using alignof, std::aligned_storage, or std::align. The following code compiles, but neither VC12 nor Clang 3.2 produce the sequence of zeros as output that would indicate that my alignment request is being respected. (gcc 4.8.1 lacks std::align, but if you comment that part out, the code compiles under gcc 4.8.1 and also produces output indicating that my alignment requests are being ignored.)

#include <iostream>
#include <memory>

int main()
{
  // Try using alignas on the allocation
  {
    class Widget {};

    for (int i = 0; i < 5; ++i)
      {
        auto ptr = new alignas(64) Widget;
        std::cout << (long)ptr % 64 << '\n';    // should be 0
      }
  }

  // Try using alignas on the type
  {
    class alignas(64) Widget {};

    for (int i = 0; i < 5; ++i)
      {
        auto ptr = new Widget;
        std::cout << (long)ptr % 64 << '\n';    // should be 0
      }
  }

  // Try using std::aligned_storage
  {
    class Widget {};

    using WidgetStorage_t = 
      std::aligned_storage<sizeof(Widget), 64>::type;

    for (int i = 0; i < 5; ++i)
      {
        auto ptr = new WidgetStorage_t;         // get buffer
        new (ptr) Widget;                       // construct Widget
        std::cout << (long)ptr % 64 << '\n';    // should be 0
      }
  }

  // Try using operator new + std::align
  {
    class Widget {};

    for (int i = 0; i < 5; ++i)
      {
        auto requestSize =      // double space to ensure that a
          2 * sizeof(Widget);   // Widget fits after ptr adjustment

        auto ptr = operator new(requestSize);   // get buffer

        std::align(64, sizeof(Widget),          // align ptr 
                   ptr, requestSize);           // inside buffer

        new (ptr) Widget;                       // construct Widget

        std::cout << (long)ptr % 64 << '\n';    // should be 0
      }
  }
}

UPDATE: My code for testing std::align is incorrect above. The following replacement code works:

 // Try using operator new + std::align
  {
    class Widget {};

    for (int i = 0; i < 5; ++i)
      {
        auto requestSize =       // ensure that a
          sizeof(Widget) + 64;   // Widget fits after ptr adjustment

        auto ptr = operator new(requestSize);   // get buffer

        std::align(64, sizeof(Widget),          // align ptr 
                   ptr, requestSize);           // inside buffer

        new (ptr) Widget;                       // construct Widget

        std::cout << (long)ptr % 64 << '\n';    // should be 0
      }
  }

Is this the only way to get the job done? It's a lot more complicated than I'd like, because now two pointers have to be tracked: the adjusted one that points to the object (necessary to destroy the constructed object) and the unadjusted one that points to the memory buffer (necessary for releasing the memory).

Community
  • 1
  • 1
KnowItAllWannabe
  • 12,972
  • 8
  • 50
  • 91
  • What is this weird looking code you have `class alignas(64) Widget {};`? – smac89 Feb 20 '14 at 03:17
  • That's the way to say that `Widget` objects have 64-byte alignment, though it doesn't seem to have any effect for heap objects. The empty curly braces are the body of the class. For this example, I don't care what's in the class. – KnowItAllWannabe Feb 20 '14 at 03:20
  • Have you considered writing a type-specific `operator new[]`, rather than forcing each place of allocation to worry about alignment? – Tony Delroy Feb 20 '14 at 03:44
  • I'm interested in whether there is a way to do this on a per-object basis (as opposed to per-type, which is what you're suggesting). For non-heap objects, this is clearly possible (via `alignas`). For heap objects, `alignas` seems to have no effect (both for objects and for types). – KnowItAllWannabe Feb 20 '14 at 03:47
  • Per object? A function with your allocation code above gives concise usage, and your remaining problem is...? Maybe to `delete` the pointer without client code worrying whether it's been tweaked? The only ways to do: override `delete` to potentially tweak the pointer back to the pre-extended-alignment value `new` originally provided (bookkeeping needed), or make sure you only use the sufficiently-aligned values `new` returns (e.g. looping to discard away lesser-aligned pointers, but how long might you loop?). Sans `delete`, could use give callers a custom smart-pointer. – Tony Delroy Feb 20 '14 at 05:20

2 Answers2

1

One option I've seen used in practice is to over-allocate, then align things for yourself.

For example, let's say you want to allocate N bytes aligned to M byte boundaries. You can proceed by allocate N+M-1 bytes, then find the first M-byte aligned address in the allocated space. For example, you can do something like:

const size_t N = sizeof(Widget);
const size_t M = 64;
char *pc = new char[N+M-1];
char *pc_aligned = (pc+M-1)&(~(M-1));
Widget *p = new (pc_aligned) Widget();    // placement new
// ...
p->~Widget();                             // explicitly call destructor
delete [] pc;                             // delete array allocated with new
Nicu Stiurca
  • 8,747
  • 8
  • 40
  • 48
0

MS clearly document that C++11 alignas is unimplemented at http://msdn.microsoft.com/en-us/library/hh567368.aspx

For GNU - seems it works if you put it in the right place - from Where can I use alignas() in C++11? just a taste - see that answer for many more examples and discussion:

typedef float aligned_block alignas(16) [4];
typedef float aligned_block [4] alignas(16);
Community
  • 1
  • 1
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • I don't see any examples in http://stackoverflow.com/questions/15788947/where-can-i-use-alignas-in-c11 that pertain to heap objects. Am I overlooking them? – KnowItAllWannabe Feb 20 '14 at 02:49
  • @KnowItAllWannabe If you tell the compiler that particular alignment of an object is needed, `new` must honour that up to `alignof(std::max_align_t)`, beyond which "If the alignment associated with a specific over-aligned type is not supported by an allocator, instantiation of the allocator for that type may fail. The allocator also may silently ignore the requested alignment.", which basically means you're back to orchestrating it manually per SchighSchagh's answer. The thrust of this answer is to describe compiler support and notation for `alignas`. – Tony Delroy Feb 20 '14 at 03:37
  • I believe that the text you cite applies only to STL allocators, not to `operator new`. I'd hope that 3.11/9 would apply here: "If a request for a specific extended alignment in a specific context is not supported by an implementation, the program is ill-formed. Additionally, a request for runtime allocation of dynamic storage for which the requested alignment cannot be honored shall be treated as an allocation failure." – KnowItAllWannabe Feb 20 '14 at 03:44
  • The default `operator new` is the default allocator for Standard Library containers so it must satisfy at least the same requirements. Well spotted though - 3.11/9 looks applicable: "If...is not support...ill-formed" means they're obliged to issue a warning message if unsupported. You could still try lodging bug reports for the compilers, if you've patience and optimism. – Tony Delroy Feb 20 '14 at 03:54
  • BTW, per http://blogs.msdn.com/b/vcblog/archive/2013/11/18/announcing-the-visual-c-compiler-november-2013-ctp.aspx, the November 2013 CTP version of the MS compiler supports `alignas`. – KnowItAllWannabe Feb 20 '14 at 03:56
  • Re CTP: good to know it's on the horizon for a proper production release. – Tony Delroy Feb 20 '14 at 04:00
  • The default allocator for the Standard Library is `std::allocator`, not `::operator new`. The former calls the latter, but that's not the same as their being the same entity. I suspect that `std::allocator::allocate` could check for an invalid alignment request and fail without calling `::operator new`, though I don't know how it would receive such a request, because I don't see a way to communicate alignment requests to `std::allocator::allocate` (or, for that matter, to `operator new`). – KnowItAllWannabe Feb 20 '14 at 04:04
  • @KnowItAllWannabe: I used "allocator" in the general sense of the function-allocating-memory, not per Allocator or `std::allocator`, so my statement was correct, but that's for the lesson ;-P. Re how alignment information could be passed... if supported, implementation defined... ultimately the compiler knows stuff and ships with a Standard Library implementation, it can orchestrate it if it wants to. Maybe the awkwardness of it all is why you're seeing implementations that don't. Anyway, elsewhere I suggested an operator `new` specific to the type, so it knows the alignment requirement.... – Tony Delroy Feb 20 '14 at 05:05
  • I replied to your class-specific `operator new` suggestion after you made it. The problem there is that it's a class-specific solution, and I'm looking for an object-specific solution. – KnowItAllWannabe Feb 20 '14 at 05:09
  • The standard only requires `alignas` support up to 16 bytes, which means asking for 64 byte alignment is not guaranteed to work (in fact, no GNU, Clang, Intel or MS compiler supports it at this time). – Levi Morrison Jun 20 '15 at 04:15