Размещение - новое выравнивание адреса

Согласно https://isocpp.org/wiki/faq/dtors#placement-new адрес, переданный в place-new, должен быть правильно выровнен. Но пример, который он дает, кажется, противоречит этому.

char memory[sizeof(Fred)];

Этот буфер, скорее всего, не выровнен для Fred, так как он немой char[], поэтому memory может указывать на почти везде. Затем он размещает новые по этому адресу.

Является ли пример противоречащим требованию выравнивания, указанному в сноске DANGER?

Это приводит к связанному с ним вопросу:

Как создать буфер (стек или кучу) выровненный для типа T (для использования в новом месте размещения одного или нескольких объектов T)?

В буфере я имею в виду буфер char[] или void* некоторого размера, а не T[], потому что это будет распределение объектов, которое впоследствии побеждает точку после размещения. new.

Спасибо.

Ответ 1

Используйте ключевое слово alignas:

alignas(Fred) char buf[sizeof(Fred)];
::new (static_cast<void*>(buf)) Fred;

Или используйте std::aligned_storage, если вы предпочитаете библиотечную оболочку вокруг этой конструкции.

Ответ 2

О вашем первом вопросе: в соответствии с ответами на этот связанный вопрос да, пример получил это неправильно:

Статически распределенные массивы выравниваются по байтам sizeof (element_type) - для char это 1 байт, который в основном не гарантирует выравнивания.

таким образом, массив char memory[sizeof(Fred)] не имеет гарантий выравнивания для Fred.

Правильный способ сделать это следующим образом (С++ 11):

alignas(Fred) char memory[sizeof(Fred)];

Ответ 3

Для распределений кучи просто используйте std::malloc, который гарантированно выделяет память, которая выровнена для любого типа.

Для распределения стека, если у вас есть доступ к С++ 11, вы можете использовать alignas, как в

alignas(T) uint8_t data[sizeof(T)];

Если у вас нет доступа к С++ 11, вы должны вернуться к конкретным атрибутам компилятора как GCC __attribute__((aligned(N))).