alignas keyword not respected
Asked Answered
P

2

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?

Protamine answered 12/2, 2016 at 14:55 Comment(13)
"It is implementation-defined whether over-aligned types are supported ([basic.align]).". See also CWG issue 2130.Railing
@Railing That looks like it should be an answer.Midwest
@Railing How do I know if an implementation supports it (apparently neither gcc nor clang do)Protamine
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().Aristophanes
@HansPassant Is that only for new? If I create a W on the stack, will it be guaranteed 64-bytes aligned?Protamine
Yes, the compiler can control that, it picks stack offsets.Aristophanes
@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 clientsBalbur
As a remark, I cannot reproduce using CLang 3.4.1 on a FreeBSD 10.1: your program correctly gives 0 1000Citronellal
Related proposal: open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0035r1.htmlRailing
It is interesting that here alignof( W ) returns 64, i.e. the requested alignment rather than the actual one, 16. (gcc 5.2.1)Multitude
@Railing 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. :-)Samsun
@Samsun Whoever operates wg21.link recently changed it to be useless to mere mortals (at least for CWG issues). /sigh open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2130Railing
@Railing Thanks! And now I remember: Apparently this is resolved for C++17: https://mcmap.net/q/18935/-what-are-the-new-features-in-c-17 I don't know whether this will be considered a defect to be fixed retroactively in earlier Standards?Samsun
C
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.

Coparcenary answered 30/6, 2016 at 20:47 Comment(0)
S
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.

Samsun answered 30/6, 2016 at 21:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.