7

I want to overalign my type on a cache boundary, so I used alignas:

struct alignas(64) W { };

This compiles fine. But then, to my surprise, when I try to allocate a bunch of Ws, they're not 64-byte aligned but actually 16-byte aligned:

#include <iostream>
#include <iomanip>
#include <unordered_map>

struct alignas(64) W { };

int main() {
    std::unordered_map<int, int> offset;

    for (int i = 0; i < 1000; ++i) {
        auto w = new W;
        offset[(uintptr_t)w % 64]++;
    }   

    for (const auto& p : offset) {
        std::cout << p.first << ' ' << p.second << '\n';
    }   
}

Yields:

0 250
16 250
32 250
48 250

on several compiles (gcc 4.8.2, gcc 5.2.0, clang 3.7.1). What's up? I told it to align, why isn't it aligning?

Barry
  • 286,269
  • 29
  • 621
  • 977
  • 5
    ["It is implementation-defined whether over-aligned types are supported (\[basic.align\])."](http://eel.is/c++draft/expr.new#1). See also [CWG issue 2130](http://wg21.link/cwg2130). – T.C. Feb 12 '16 at 15:01
  • 1
    @T.C. That looks like it should be an answer. – NathanOliver Feb 12 '16 at 15:18
  • @T.C. How do I know if an implementation supports it (apparently neither gcc nor clang do) – Barry Feb 12 '16 at 15:28
  • 7
    operator new is borken, the compiler knows the alignment requirement but has no way to tell the operator about it. So this is pretty much guaranteed to go wrong. It's your burden to work around it, something like aligned_alloc() or posix_memalign() or _aligned_malloc(). – Hans Passant Feb 12 '16 at 15:30
  • @HansPassant Is that only for `new`? If I create a `W` on the stack, will it be guaranteed 64-bytes aligned? – Barry Feb 12 '16 at 15:47
  • 4
    Yes, the compiler can control that, it picks stack offsets. – Hans Passant Feb 12 '16 at 15:48
  • 2
    @HansPassant To add to that recommendation, you can probably create an `operator new` and `operator delete` inside `struct W` that call `aligned_alloc` and `aligned_free` internally without complicating the job for external clients – KABoissonneault Feb 12 '16 at 21:09
  • As a remark, I cannot reproduce using CLang 3.4.1 on a FreeBSD 10.1: your program correctly gives `0 1000` – Serge Ballesta Feb 13 '16 at 10:36
  • Related proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0035r1.html – T.C. Feb 22 '16 at 09:38
  • 1
    It is interesting that here `alignof( W )` returns 64, i.e. the _requested alignment_ rather than the actual one, 16. (gcc 5.2.1) – Aelian Mar 21 '16 at 17:28
  • @T.C. Do you have a link that doesn't require us to log in as part of "the WG21 ISO standards committee and its invited members"? Perhaps mercifully, most of us are neither of those things. :-) – underscore_d Jun 30 '16 at 21:03
  • @underscore_d Whoever operates wg21.link recently changed it to be useless to mere mortals (at least for CWG issues). /sigh http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2130 – T.C. Jun 30 '16 at 21:05
  • @T.C. Thanks! And now I remember: Apparently this is **resolved for C++17**: http://stackoverflow.com/a/38060437/2757035 I don't know whether this will be considered a defect to be fixed retroactively in earlier Standards? – underscore_d Jun 30 '16 at 21:08

2 Answers2

3

This is answered nicely here: https://stackoverflow.com/a/16510895

Basically: new (at least in its normal usage) only guarantees a constant maximum alignment (alignof(std::max_align_t)) for every call to new.

Community
  • 1
  • 1
ajneu
  • 432
  • 3
  • 8
2

The other answer is correct in the sense that it explains the existing limitation, but I'd like to point out that things are about to get better.

As indicated by T.C. in the comments, this was a long-standing deficiency in the language. It looks like the WG effort to fix this has led to a resolution in C++17 (which has just attained feature-complete status). Thus, when compiling to that Standard, overalignment will finally be respected by dynamic allocation, by using the new std::align_val_t overloads of new. Thus solving Barry's problem!

Given the amount of new scaffolding required, I presume this won't be backported to earlier versions of the Standard, so the old caveat about their dynamic allocation only sufficing for types having fundamental alignment will presumably remain true.

Community
  • 1
  • 1
underscore_d
  • 6,309
  • 3
  • 38
  • 64