Зачем вам вообще использовать alloca(), когда вы всегда можете выделить в стеке буфер фиксированного размера, достаточно большой для всех целей? Это не риторический вопрос...
В каких случаях alloca() полезен?
Ответы (6)
Это может быть полезно, если размер буфера меняется во время выполнения или если он вам нужен только иногда: в целом это будет использовать меньше места в стеке, чем буфер фиксированного размера при каждом вызове. Особенно, если функция находится высоко в стеке или рекурсивна.
Возможно, вы захотите использовать его, если нет возможности узнать максимальный размер, который вам может понадобиться во время компиляции.
должны ли вы другой вопрос - это не стандарт, и нет способа определить, может ли это вызвать переполнение стека.
Никогда - это не часть C++ и бесполезно в C. Однако вы не можете выделить "статический буфер в стеке" - статические буферы выделяются во время компиляции, а не в стеке.
Суть alloca(), конечно же, в том, что она не имеет фиксированного размера, она находится в стеке и автоматически освобождается при выходе из функции. И в C++, и в C есть лучшие механизмы для этого.
В каких случаях alloca() полезен?
Единственный раз, когда я когда-либо видел использование alloca, был в Open Dynamics Engine. Насколько я знаю, они выделяли ОГРОМНЫЕ матрицы (поэтому скомпилированной программе может потребоваться стек 100 МБ), которые автоматически освобождались при возврате функции (для меня это выглядит как грабеж смартпойнтера). Это было довольно давно.
Хотя это, вероятно, было намного быстрее, чем new/malloc, я все же думаю, что это была плохая идея. Вместо того, чтобы вежливо исчерпать ОЗУ, программа могла аварийно завершать работу с переполнением стека (т.е. вводя в заблуждение), когда сцена становилась слишком сложной для обработки. Нехорошее поведение, IMO, особенно для физического движка, когда вы можете легко ожидать, что кто-то бросит в сцену несколько тысяч кирпичей и посмотрите, что произойдет, когда они все столкнутся одновременно. Кроме того, вам нужно было установить размер стека вручную - т.е. в системе с большим объемом оперативной памяти программа все равно была бы ограничена размером стека.
буфер фиксированного размера в стеке, достаточно большой для всех целей? Это не риторический вопрос...
Если вам нужен буфер фиксированного размера для всех целей, вы также можете поместить его в статическую/глобальную переменную или использовать память кучи.
alloca
использовал машину времени, чтобы украсть идею. alloca
относится к концу 1960-х годов, а интеллектуальные указатели - к 1986 году... В другом месте было сказано о безопасности потоков как о положительном результате распределения, которое статические/глобальные переменные не разделяют. Куча зависит от того, как вы ее используете, поэтому не обращайтесь к ней с помощью 900 символов.
- person Heath Hunnicutt; 10.08.2010
Функция alloca()
практически никогда не нужна; для целей распределения памяти вы можете использовать malloc()
/free()
в C (или один из наборов возможностей в C++) и добиться практически такого же практического эффекта. Преимущество этого заключается в том, что он лучше справляется с меньшим размером стека.
Однако я видел[1] одно законное (хотя и хакерское!) его использование: для обнаружения потенциального переполнения стека в Windows; если выделение (количества ненужного пространства, к которому вы хотели получить доступ) не удалось, вы выбыли, но у вас было достаточно места для изящного восстановления. Он был обернут в __try
/__except
, чтобы не зависал, и нуждался в дополнительных хитростях ассемблера, чтобы избежать проблем, вызванных gcc. Как я уже сказал, взлом. Но умный, это единственное правильное использование alloca()
, которое я когда-либо видел.
Но не делай этого. Лучше написать код, чтобы не нужны были такие игры.
[1] Это было в Tcl 8.4 (и, возможно, в более ранних версиях Tcl). В более поздних версиях он был удален. Более поздние версии удалили его, потому что он был привередливым, очень сложным и вызывал серьезные проблемы. 8.6 использует бесстековую реализацию исполняющего движка вместо такого рода фанковости.
Использование alloca()
может быть разумным, когда вы не можете надежно использовать malloc()
(или new
в C++, или другой распределитель памяти) или вообще не можете, но вы можете предположить, что в вашем стеке доступно больше места, т.е. , когда вы действительно ничего не можете сделать.
Например, в файле glibc
segfault.c имеем:
/* This function is called when a segmentation fault is caught. The system
is in an unstable state now. This means especially that malloc() might
not work anymore. */
static void
catch_segfault (int signal, SIGCONTEXT ctx)
{
void **arr;
/* ... */
/* Get the backtrace. */
arr = alloca (256 * sizeof (void *));
/* ... */
}