После использования вектора 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?
}
Функция 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
, который никогда не перераспределяет элементы (за счет немного более медленного доступа).