Ключевое слово alignas не соблюдается
Я хочу перенастроить мой тип на границе кэша, поэтому я использовал alignas
:
struct alignas(64) W { };
Это хорошо компилируется. Но потом, к моему удивлению, когда я пытаюсь выделить кучу W
s, они не выровнены на 64 байта, но на самом деле выровнены на 16 байтов:
#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';
}
}
Урожайность:
0 250
16 250
32 250
48 250
на нескольких компиляциях (gcc 4.8.2, gcc 5.2.0, clang 3.7.1). Что происходит? Я сказал это для выравнивания, почему это не выравнивание?
2 ответа
На этот вопрос приятно ответить здесь: /questions/7688646/dinamicheskoe-vyiravnivanie-pamyati-v-c11/7688651#7688651
В принципе: new
(по крайней мере, при обычном использовании) только гарантирует постоянное максимальное выравнивание (alignof(std::max_align_t)
) за каждый звонок new
,
Другой ответ является правильным в том смысле, что он объясняет существующее ограничение, но я хотел бы отметить, что ситуация скоро улучшится.
Как указано TC в комментариях, это был давний недостаток в языке. Похоже, что попытка WG это исправить привела к разрешению в C++17 (которое только что достигло состояния полной функциональности). Таким образом, при компиляции к этому стандарту, перераспределение будет в конечном итоге учитываться путем динамического распределения с использованием нового std::align_val_t
перегрузки new
, Таким образом, решение проблемы Барри!
Принимая во внимание количество новых необходимых лесов, я предполагаю, что это не будет перенесено в более ранние версии Стандарта, поэтому старая оговорка об их динамическом размещении, достаточная только для типов, имеющих фундаментальное выравнивание, предположительно останется верной.