Документация для _alloca()
говорит Вот:
Процедура _alloca возвращает пустой указатель на выделенное пространство,
который гарантированно выровнен для хранения любого типа
объект.
Тем не мение, Вот это говорит:
_alloca должен быть выровнен по 16 байтов и дополнительно должен использовать указатель кадра.
Таким образом, кажется, что в первой ссылке они забыли о 32-байтовых выровненных типах AVX / AVX2, таких как __m256d
,
Еще одна вещь, которая меня смущает, это то, что первая страница _alloca()
устарела, хотя и предлагает вместо этого использовать функцию, которая может выделять память из кучи, а не из стека (что недопустимо в моем многопоточном приложении).
Так может кто-то указать мне, есть ли какой-нибудь современный (возможно, новый стандарт C / C ++?) Способ для распределения памяти с выравниванием стека?
Пояснение 1Пожалуйста, не предоставляйте решения, которые требуют, чтобы размер массива был постоянным во время компиляции. Моя функция выделяет переменное количество элементов массива в зависимости от значения параметра во время выполнения.
Выделите с помощью _alloca (), затем выровняйте вручную. Как это:
const int align = 32;
void *p =_alloca(n + align - 1);
__m256d *pm = (__m256d *)((((int_ptr_t)p + align - 1) / align) * align);
замещать const
с #define
, если необходимо.
C ++ 11 представил alignof
оператор:
Выражение alignof приводит к требованию выравнивания его типа операнда.
Вы можете использовать его следующим образом:
struct s {};
typedef s __attribute__ ((aligned (64))) aligned_s;
std::cout << alignof(aligned_s); // Outputs: 64
Замечания: Если выравнивание вашего типа больше его размера, компилятор не позволит вам объявить массивы типа массива (Подробнее Вот):
ошибка: выравнивание элементов массива больше размера элемента
Но, если выравнивание вашего типа меньше его размера, вы можете
смело выделяйте массивы:
aligned_s arr[32];
-- OR --
constexpr size_t arr_size = 32;
aligned_s arr[arr_size];
Компиляторы, которые поддерживают VLA, также разрешат компиляторы для вновь определенного типа.
«Современный» способ это:
Не делайте выделение переменной длины в стеке.
В контексте вашего вопроса — желая выделить в куче, но воздерживаться от этого — я предполагаю, что вы, возможно, выделяете больше, чем какой-то небольшой постоянный объем памяти во время компиляции. В этом случае, вы просто собираетесь разбить свой стек с этим alloca()
вызов. Вместо этого используйте потокобезопасный распределитель памяти. Я уверен, что для этого есть библиотеки на GitHub (и в худшем случае вы можете защитить вызовы выделения глобальным мьютексом, хотя это и медленно, если вам нужно их много).
С другой стороны, если вы заранее знаете, каков предел размера выделения — просто предварительно выделите столько памяти в локальном потоке; или использовать локальный массив фиксированного размера (который будет размещен в стеке).
_alloca()
безусловно, не является стандартным или переносимым способом обработки выравнивания в стеке. К счастью, в C ++ 11 мы получили alignas
а также std::aligned_storage
, Ни одно из этих действий не заставляет вас что-либо класть в кучу, поэтому они должны работать для вашего варианта использования. Например, чтобы выровнять массив структур по границе 32 байта:
#include <type_traits>
struct bar { int member; /*...*/ };
void fun() {
std::aligned_storage<sizeof(bar), 32>::type array[16];
auto bar_array = reinterpret_cast<bar*>(array);
}
Или, если вы просто хотите выровнять одну переменную в стеке по границе:
void bun() {
alignas(32) bar b;
}
Вы также можете использовать alignof
оператор, чтобы получить требования выравнивания для данного типа.