Допустимо ли это использование alloca()?
После использования вектора std для хранения моего списка ходов в шахматном движке я понял, что, поскольку у шахмат есть коэффициент усреднения 35 (т.е. что-то вроде 35 легальных ходов из типичной позиции), вектор сильно менял размеры, тем самым отрицательно влияя на производительность генератора хода. Одним из способов обойти это (что я понял только сегодня) является резервирование минимальной емкости для вектора. Однако возможность использования alloca() привлекла мое внимание. Вероятно, это очень простой вопрос, но документации по alloca() довольно мало, и очень мало примеров того, как его использовать.
Таким образом, в ответе " Распределение классов с переменным размером" упоминается, что распределение стека не может быть изменено. Тем не менее, будет ли верно следующее?
struct MoveList
{
MoveList(): capacity(10)
{
moves = (Move*) alloca(sizeof(Move) * 10);
}
void resize()
{
capacity *= 2;
moves = (Move*) alloca(sizeof(Move) * capacity );
}
void push_back();
Move* moves;
int size;
int capacity;
}
В частности, если, скажем, емкость 10 недостаточна для alloca() в первый раз, синтаксически допустимо (и правильно) просто снова вызывать alloca(), чтобы выделить больше памяти? Даст ли этот метод лучшую производительность (по сравнению со стандартным вектором с помощью Reserve()) или только увеличит вероятность переполнения стека? Моей структуре Move требуется около 28 байт памяти, и я подозреваю, что движок будет рекурсивно искать (используя альфа-бета) максимум до 7 или 8 слоев, так что, возможно, из стека будет использоваться максимум 28 * 35 * 8 ~ 8 КБ., Я где-то читал, что обычно стеки имеют ограничение в 1 Мб, так что это не должно быть слишком много, верно?
Изменить: Благодаря ответам ниже, я теперь понимаю, что мое первоначальное понимание того, что делал alloca(), было неверным. Однако я все еще хотел бы знать, возможно ли использовать alloca() следующим образом:
int main()
{
int* arr = (int) alloca(sizeof(int));
arr = alloca(sizeof(int) * 2 ));//is this 'resizing' valid?
}
2 ответа
Функция alloca
выделяет память в стеке, и память больше не доступна, как только функция, в которой alloca
назывался возврат. Это означает, что как только MoveList
конструктор или resize
функция возвращает, память больше не доступна. Ваше предположение, что каким-то образом вы сможете использовать эту память в течение жизни MoveList
объект не так.
Лучший вариант для вас это использовать std::vector
и резерв.
Вы, кажется, не понимаете, что нестандартное alloca()
выражение на самом деле делает. Он выделяет память в кадре стека вызывающей функции. В вашем случае это означает, что время жизни выделенного пространства (в этом случае назначается moves
член) это конструктор:
MoveList(): capacity(10)
{
moves = (Move*) alloca(sizeof(Move) * 10);
... moves is valid from this point
// "moves" stops being valid at this point
}
Поскольку остальная часть вашего конструктора пуста, это не то, что вы хотели. (Также, alloca()
имеет побочный эффект предотвращения включения вызывающей функции - еще один непреднамеренный побочный эффект.) Другими словами, чтобы ответить на вопрос из заголовка, это использование alloca()
не действует
Даже если бы это было как-то сделано, так как alloca()
не имеет аналога для изменения размера или освобождения выделенной памяти (и не может иметь ее, из-за того, как она работает), это крайне неуместно в любой ситуации, когда необходимо изменить размер области - именно так вы пытаетесь ее использовать.
Изменение размера std::vector
как правило, уже факторы экспоненциального роста, поэтому добавлять свои собственные не нужно. Если вы не уверены, измерьте производительность и посмотрите, что работает для вас. Может быть, для вашего случая было бы достаточно позвонить std::vector<T>::reserve()
чтобы убедиться, что вектор начинается с оптимистичного размера, устраняя необходимость в перераспределении. Или используйте std::deque
, который никогда не перераспределяет элементы (за счет немного более медленного доступа).