Выделите выровненную память в стеке как _alloca

Документация для _alloca() говорит Вот:

Процедура _alloca возвращает пустой указатель на выделенное пространство,
который гарантированно выровнен для хранения любого типа
объект.

Тем не мение, Вот это говорит:

_alloca должен быть выровнен по 16 байтов и дополнительно должен использовать указатель кадра.

Таким образом, кажется, что в первой ссылке они забыли о 32-байтовых выровненных типах AVX / AVX2, таких как __m256d,

Еще одна вещь, которая меня смущает, это то, что первая страница _alloca() устарела, хотя и предлагает вместо этого использовать функцию, которая может выделять память из кучи, а не из стека (что недопустимо в моем многопоточном приложении).

Так может кто-то указать мне, есть ли какой-нибудь современный (возможно, новый стандарт C / C ++?) Способ для распределения памяти с выравниванием стека?

Пояснение 1Пожалуйста, не предоставляйте решения, которые требуют, чтобы размер массива был постоянным во время компиляции. Моя функция выделяет переменное количество элементов массива в зависимости от значения параметра во время выполнения.

0

Решение

Выделите с помощью _alloca (), затем выровняйте вручную. Как это:

const int align = 32;
void *p =_alloca(n + align - 1);
__m256d *pm = (__m256d *)((((int_ptr_t)p + align - 1) / align) * align);

замещать const с #define, если необходимо.

4

Другие решения

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, также разрешат компиляторы для вновь определенного типа.

1

«Современный» способ это:

Не делайте выделение переменной длины в стеке.

В контексте вашего вопроса — желая выделить в куче, но воздерживаться от этого — я предполагаю, что вы, возможно, выделяете больше, чем какой-то небольшой постоянный объем памяти во время компиляции. В этом случае, вы просто собираетесь разбить свой стек с этим alloca() вызов. Вместо этого используйте потокобезопасный распределитель памяти. Я уверен, что для этого есть библиотеки на GitHub (и в худшем случае вы можете защитить вызовы выделения глобальным мьютексом, хотя это и медленно, если вам нужно их много).

С другой стороны, если вы заранее знаете, каков предел размера выделения — просто предварительно выделите столько памяти в локальном потоке; или использовать локальный массив фиксированного размера (который будет размещен в стеке).

1

_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 оператор, чтобы получить требования выравнивания для данного типа.

0