В каких случаях полезно использовать alloca()?
Зачем вам когда-либо хотеть использовать alloca(), когда вы всегда можете выделить буфер фиксированного размера в стеке, достаточно большом для всех применений? Это не риторический вопрос...
6 ответов
Это может быть полезно, если размер буфера изменяется во время выполнения, или если вам это нужно только иногда: это будет занимать меньше места в стеке в целом, чем буфер фиксированного размера в каждом вызове. Особенно, если функция находится высоко в стеке или рекурсивна.
С помощью alloca()
может быть разумным, когда вы не можете использовать malloc()
(или же new
в C++ или в другом распределителе памяти) надежно или вообще, но вы можете предположить, что в вашем стеке доступно больше места, то есть когда вы больше ничего не можете сделать.
Например, в glibc
sgfault.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 *));
/* ... */
}
Возможно, вы захотите использовать его, если нет способа узнать максимальный размер, который вам может понадобиться во время компиляции.
Нужен ли вам другой вопрос - это не стандартно, и нет никакого способа определить, может ли это вызвать переполнение стека.
В каких случаях полезно использовать alloca()?
Единственный раз, когда я видел использование alloca, был в Open Dynamics Engine. AFAIK они выделяли ОГРОМНЫЕ матрицы с помощью этого (таким образом, скомпилированная программа могла требовать стека в 100 МБ), которые автоматически освобождались при возврате функции (для меня это выглядит как срыв со смарт-указателя). Это было довольно давно.
Хотя это было, вероятно, намного быстрее, чем new / malloc, я все же думаю, что это была плохая идея. Вместо вежливого запуска ОЗУ, программа могла аварийно завершить работу с переполнением стека (т.е. вводить в заблуждение), когда сцена стала слишком сложной для обработки. Неплохое поведение, IMO, особенно для физического движка, где вы можете легко ожидать, что кто-то бросит несколько тысяч кирпичей в сцену и увидит, что происходит, когда все они сталкиваются одновременно. Кроме того, вы должны были установить размер стека вручную - т.е. в системе с большим объемом оперативной памяти программа все равно будет ограничена размером стека.
буфер фиксированного размера в стеке, достаточно большой, чтобы соответствовать всем применениям? Это не риторический вопрос...
Если вам нужен буфер фиксированного размера для всех целей, вы также можете поместить его в статическую / глобальную переменную или использовать кучу памяти.
Никогда - это не является частью C++ и бесполезно в C. Однако вы не можете выделить "статический буфер в стеке" - статические буферы размещаются во время компиляции, а не в стеке.
Суть alloca(), конечно, в том, что он не имеет фиксированного размера, он находится в стеке и что он автоматически освобождается при выходе из функции. И C++, и C имеют лучшие механизмы для этого.
alloca()
функция практически не нужна; в целях выделения памяти вы можете использовать malloc()
/free()
в C (или один из набора возможностей в C++) и достичь практически того же практического эффекта. Это имеет преимущество в том, что лучше справляется с меньшими размерами стека.
Однако я видел[1] одно законное (если хакерское!) Его использование: для обнаружения потенциального переполнения стека в Windows; если выделение (того количества отстойного пространства, к которому вы хотели получить доступ) не удалось, вы вышли, но у вас было достаточно места для изящного восстановления. Было завернуто в __try
/__except
чтобы он не падал и нуждался в дополнительных хитростях ассемблера, чтобы избежать проблем, связанных с gcc. Как я уже сказал, взломать. Но умный, который является единственным допустимым использованием для alloca()
что я когда-либо видел
Но не делай этого. Лучше написать код, чтобы не нужны такие игры.
[1] Это было в Tcl 8.4 (и, возможно, в более ранних версиях Tcl). Это было удалено в более поздних версиях. Более поздние версии удалили это, потому что это было привередливым, очень хитрым и глубоко тревожащим. 8.6 использует реализацию стека механизма исполнения вместо такого рода фанки.