Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

should std::vector honour alignof(value_type)?

If I define a simple type with a certain alignment requirement, shouldn't a std::vector<t> of said type honour the alignment for every single element?

Consider the following example

typedef std::array<double,3> alignas(32) avx_point;
std::vector<avx_point> x(10);
assert(!(std::ptrdiff_t(&(x[0]))&31) &&   // assert that x[0] is 32-byte aligned
       !(std::ptrdiff_t(&(x[1]))&31));    // assert that x[1] is 32-byte aligned

I found that the alignment requirement is silently (without any warning) violated by clang 3.2 (with or without -stdlib=libc++), while gcc 4.8.0 issues a warning that it ignores the attributes on the template argument to std::vector (the intel compiler is too daft to understand alignas, but if I use __declspec(align(32)) instead, it behaves like clang). Both create code that triggers the assert.

So, is this correct behaviour or a bug of clang (and icpc) and an issue with gcc?

edit to answer a question raised in the comments: if I define

typedef typename std::aligned_storage<sizeof (avx_point),
                                      alignof(avx_point)>::type avx_storage;

I get

sizeof (avx_storage) == 32;
alignof(avx_storage) == 32;

but std::vector<avx_storage> still fails to align the first element (and hence all the others too) for clang and gcc (without warning this time). So there are apparently two issues with the implementations: first, that std::allocator<type> ignores any alignment requirements even for the first element (illegal?) and second, that no padding is applied to ensure alignment of subsequent elements.

––––––––––––

edit There is a related, more practical question for how to obtain memory suitably aligned for SSE/AVX operations. In contrast, I want to know whether std::vector<> (or std::allocator<>) shouldn't honour alignas as of the C++ standard (as of 2011). None of the answers to that other question are suitable answers to this one.

like image 739
Walter Avatar asked May 07 '13 17:05

Walter


1 Answers

first, that std::allocator ignores any alignment requirements even for the first element (illegal?)

I'm far from being an expert on allocators but it seems to me that, unfortunately, this is legal behaviour. More precisely, an allocator might ignore the requested alignment. Indeed, [allocator.requirements], 17.6.3.5/6 states:

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.

You can write your own allocator to give you aligned memory. I've done that before at my work but, unfortunately, for copyright reasons, I cannot disclose the code :-( All I can say, is the obvious thing: it was based on _aligned_malloc and _aligned_free (which are Microsoft extensions). Or you can Google for "aligned allocator" and a few options will come up, one of which is

https://gist.github.com/donny-dont/1471329

I emphasize that I'm not the author of this aligned allocator and I've never used it.

Update

The aligned allocator above is for Visual Studio/Windows but it can be used as a base for implementing aligned allocators on other platforms. You can use the posix memalign family of functions or the C11 function aligned_alloc.

See this post.

like image 85
Cassio Neri Avatar answered Sep 21 '22 07:09

Cassio Neri