Должен std::vector honor alignof(value_type)?
Если я определю простой тип с определенным требованием выравнивания, не должен ли std::vector<t>
указанного типа соблюдать выравнивание для каждого элемента?
Рассмотрим следующий пример
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
Я обнаружил, что требование выравнивания молча (без какого-либо предупреждения) нарушается clang 3.2 (с или без -stdlib=libc++
), в то время как gcc 4.8.0 выдает предупреждение, что он игнорирует атрибуты аргумента шаблона для std::vector
(компилятор Intel слишком глуп, чтобы понять alignas
, но если я использую __declspec(align(32))
вместо этого он ведет себя как лязг). Оба создают код, который запускает утверждение.
Итак, это правильное поведение или ошибка clang (и icpc) и проблема с gcc?
изменить, чтобы ответить на вопрос, поднятый в комментариях: если я определю
typedef typename std::aligned_storage<sizeof (avx_point),
alignof(avx_point)>::type avx_storage;
я получил
sizeof (avx_storage) == 32;
alignof(avx_storage) == 32;
но std::vector<avx_storage>
по-прежнему не удается выровнять первый элемент (и, следовательно, все остальные тоже) для clang и gcc (без предупреждения на этот раз). Таким образом, есть две проблемы с реализациями: во-первых, это std::allocator<type>
игнорирует любые требования выравнивания даже для первого элемента (недопустимо?) и второго, что дополнение не применяется для обеспечения выравнивания последующих элементов.
1 ответ
во-первых, этот std::allocator игнорирует любые требования выравнивания даже для первого элемента (недопустимо?)
Я далеко не эксперт по распределителям, но мне кажется, что, к сожалению, это законное поведение. Точнее, распределитель может игнорировать запрошенное выравнивание. Действительно, [allocator.requirements], 17.6.3.5/6 гласит:
Если выравнивание, связанное с конкретным переопределенным типом, не поддерживается распределителем, создание экземпляра распределителя для этого типа может завершиться ошибкой. Распределитель также может молча игнорировать запрошенное выравнивание.
Вы можете написать свой собственный распределитель, чтобы дать вам выровненную память. Я делал это раньше на своей работе, но, к сожалению, по причинам авторского права, я не могу раскрыть код:-(Все, что я могу сказать, это очевидная вещь: он был основан на _aligned_malloc
а также _aligned_free
(которые являются расширениями Microsoft). Или вы можете Google для "согласованного распределителя" и несколько вариантов, один из которых
https://gist.github.com/donny-dont/1471329
Я подчеркиваю, что я не автор этого согласованного распределителя, и я никогда не использовал его.
Обновить
Выравниваемый распределитель выше для Visual Studio/Windows, но он может использоваться в качестве основы для реализации согласованных распределителей на других платформах. Вы можете использовать posix memalign
семейство функций или функция C11 aligned_alloc
,
Смотрите этот пост.