19

My question is rather simple;

Does the alignas specifier work with 'new'? That is, if a struct is defined to be aligned, will it be aligned when allocated with new?

Flow
  • 23,572
  • 15
  • 99
  • 156
Skeen
  • 4,614
  • 5
  • 41
  • 67

2 Answers2

17

Before C++17, if your type's alignment is not over-aligned, then yes, the default new will work. "Over-aligned" means that the alignment you specify in alignas is greater than alignof(std::max_align_t). The default new will work with non-over-aligned types more or less by accident; the default memory allocator will always allocate memory with an alignment equal to alignof(std::max_align_t).

If your type's alignment is over-aligned however, your out of luck. Neither the default new, nor any global new operator you write, will be able to even know the alignment required of the type, let alone allocate memory appropriate to it. The only way to help this case is to overload the class's operator new, which will be able to query the class's alignment with alignof.

Of course, this won't be useful if that class is used as the member of another class. Not unless that other class also overloads operator new. So something as simple as new pair<over_aligned, int>() won't work.

C++17 adds a number of memory allocators which are given the alignment of the type being used. These allocators are used specifically for over-aligned types (or more specifically, new-extended over-aligned types). So new pair<over_aligned, int>() will work in C++17.

Of course, this only works to the extent that the allocator handles over-aligned types.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 4
    To add: One can query this maximum alignment via `alignof(std::max_align_t)`. Types with alignments greater than this are called *over-aligned* and their support is conditional, implementation-defined. – GManNickG Mar 19 '13 at 23:11
  • Turns out I actually don't need this, however it's nice to know anyway! – Skeen Mar 20 '13 at 00:11
  • Can one do anything to raise the limit, for maximum alignment say in g++? – Skeen Mar 20 '13 at 00:30
  • @Skeen: "*Can one do anything to raise the limit, for maximum alignment say in g++?*" There may be some GCC setting for it, but I rather doubt it. What do you need such highly over-aligned types for anyway? – Nicol Bolas Mar 20 '13 at 08:20
  • 1
    @NicolBolas: PageTables on x86 needs to be aligned on page boundaries (0x1000). – Skeen Mar 20 '13 at 12:19
  • @Skeen: Yes, but that doesn't explain why you need a *type* for that. You allocate a page or two from the OS, and you call the OS function to copy the page table to/from this memory. – Nicol Bolas Mar 20 '13 at 12:22
  • 1
    @NicolBolas What is the proper syntax to combine alignas with new? I tried the following char* a = alignas(alignment) new char[N] but this says "expected primary-expression before 'alignas'" I have not been able to find a syntax example online. – sunny Jul 31 '15 at 14:16
  • 1
    @sunny There's none. `void* operator new(std::size_t count)` has no direct way of acquiring the user-specified alignment. Unless you encode the alignment into the count, but that's highly erroneous. Or you can write a custom placement-new operator that accepts an extra `size_t` for the alignment. – bit2shift Aug 01 '15 at 23:09
  • This answer is wrong, move along and see the next one. – Lorenzo Pistone Apr 29 '16 at 14:08
  • @LorenzoPistone: My original answer was true for non-over-aligned type (not that I actually said that, of course). The new version is correct for all types. – Nicol Bolas Apr 29 '16 at 14:43
16

No it does not. The struct will be padded to the alignment requested, but it will not be aligned. There is a chance, however, that this will be allowed in C++17 (the fact that this C++17 proposal exists should be pretty good proof this can't work in C++11).

I have seen this appear to work with some memory allocators, but that was pure luck. For instance, some memory allocators will align their memory allocations to powers of 2 of the requested size (up to 4KB) as an optimization for the allocator (reduce memory fragmentation, possibly make it easier to reuse previously freed memory, etc...). However, the new/malloc implementations that are included in the OS X 10.7 and CentOS 6 systems that I tested do not do this and fail with the following code:

#include <stdlib.h>
#include <assert.h>

struct alignas(8)   test_struct_8   { char data; };
struct alignas(16)  test_struct_16  { char data; };
struct alignas(32)  test_struct_32  { char data; };
struct alignas(64)  test_struct_64  { char data; };
struct alignas(128) test_struct_128 { char data; };
struct alignas(256) test_struct_256 { char data; };
struct alignas(512) test_struct_512 { char data; };

int main() {
   test_struct_8   *heap_8   = new test_struct_8;
   test_struct_16  *heap_16  = new test_struct_16;
   test_struct_32  *heap_32  = new test_struct_32;
   test_struct_64  *heap_64  = new test_struct_64;
   test_struct_128 *heap_128 = new test_struct_128;
   test_struct_256 *heap_256 = new test_struct_256;
   test_struct_512 *heap_512 = new test_struct_512;

#define IS_ALIGNED(addr,size)   ((((size_t)(addr)) % (size)) == 0)

   assert(IS_ALIGNED(heap_8, 8));
   assert(IS_ALIGNED(heap_16, 16));
   assert(IS_ALIGNED(heap_32, 32));
   assert(IS_ALIGNED(heap_64, 64));
   assert(IS_ALIGNED(heap_128, 128));
   assert(IS_ALIGNED(heap_256, 256));
   assert(IS_ALIGNED(heap_512, 512));

   delete heap_8;
   delete heap_16;
   delete heap_32;
   delete heap_64;
   delete heap_128;
   delete heap_256;
   delete heap_512;

return 0;
}
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Thiago
  • 571
  • 1
  • 5
  • 5
  • 3
    This is correct, the top answer is not. C++11 *will* give you the correct alignment for stack allocated objects but the default memory allocators will not give you correct alignment. So for now, you have to use POSIX/windows functions wrapped in OS detection macros. Eg; posix_memalign on Linux/OSX/BSD and aligned_alloc on Windows. For people using Intel MKL, there's mkl_malloc and mkl_free. – alfalfasprout Mar 24 '16 at 16:17