В каких случаях alloca() полезен?

Зачем вам вообще использовать alloca(), когда вы всегда можете выделить в стеке буфер фиксированного размера, достаточно большой для всех целей? Это не риторический вопрос...


person zr.    schedule 10.08.2010    source источник
comment
см. также stackoverflow.com/questions /1018853/   -  person Gregory Pakosz    schedule 10.08.2010
comment
«goto» также считается плохой практикой, но иногда это необходимо. Всегда ли нужен alloca()?   -  person zr.    schedule 11.08.2010


Ответы (6)


Это может быть полезно, если размер буфера меняется во время выполнения или если он вам нужен только иногда: в целом это будет использовать меньше места в стеке, чем буфер фиксированного размера при каждом вызове. Особенно, если функция находится высоко в стеке или рекурсивна.

person Andy Mortimer    schedule 10.08.2010
comment
+1 за самый убедительный ответ на данный момент. Когда функция является рекурсивной, выделение максимально возможного необходимого размера буфера в стеке может значительно уменьшить количество максимальных рекурсивных вызовов. Таким образом, использование alloca() может уменьшить штраф от необходимости иметь дело с наихудшим сценарием. - person zr.; 11.08.2010
comment
Не могли бы вы подробнее рассказать об этом? - person KodeWarrior; 21.09.2012

Возможно, вы захотите использовать его, если нет возможности узнать максимальный размер, который вам может понадобиться во время компиляции.

должны ли вы другой вопрос - это не стандарт, и нет способа определить, может ли это вызвать переполнение стека.

person Mike Seymour    schedule 10.08.2010
comment
похлопать по плечу за переполнение стека! - person Ryan Tenney; 10.08.2010

Никогда - это не часть C++ и бесполезно в C. Однако вы не можете выделить "статический буфер в стеке" - статические буферы выделяются во время компиляции, а не в стеке.

Суть alloca(), конечно же, в том, что она не имеет фиксированного размера, она находится в стеке и автоматически освобождается при выходе из функции. И в C++, и в C есть лучшие механизмы для этого.

person Community    schedule 10.08.2010
comment
Zr отредактировал вопрос? Теперь он читается с фиксированным размером, а не статическим - person Shog9; 10.08.2010
comment
alloca является частью C++ не в меньшей степени, чем C, — ни в том, ни в другом он не стандартизирован. - person Heath Hunnicutt; 10.08.2010
comment
@shog9 - если бы вопрос был отредактирован, мы бы увидели его обозначение. Мы не. - person Heath Hunnicutt; 10.08.2010
comment
@Heath Он был отредактирован - в пределах начального предела, который не отображается в истории редактирования. - person ; 10.08.2010
comment
@Heath: как отмечает Нил, после публикации или редактирования есть льготный период, в течение которого изменения, внесенные автором / последним редактором, не создают отдельную запись о редакции. Учитывая, что Нил и zr опубликовали сообщения с разницей в пару минут, я подумал, что, скорее всего, это произошло... - person Shog9; 10.08.2010
comment
да, я отредактировал вопрос. Под «статическим» я имел в виду «фиксированный размер, известный во время компиляции», а не «статический», как ключевое слово c/c++. - person zr.; 11.08.2010

В каких случаях alloca() полезен?

Единственный раз, когда я когда-либо видел использование alloca, был в Open Dynamics Engine. Насколько я знаю, они выделяли ОГРОМНЫЕ матрицы (поэтому скомпилированной программе может потребоваться стек 100 МБ), которые автоматически освобождались при возврате функции (для меня это выглядит как грабеж смартпойнтера). Это было довольно давно.

Хотя это, вероятно, было намного быстрее, чем new/malloc, я все же думаю, что это была плохая идея. Вместо того, чтобы вежливо исчерпать ОЗУ, программа могла аварийно завершать работу с переполнением стека (т.е. вводя в заблуждение), когда сцена становилась слишком сложной для обработки. Нехорошее поведение, IMO, особенно для физического движка, когда вы можете легко ожидать, что кто-то бросит в сцену несколько тысяч кирпичей и посмотрите, что произойдет, когда они все столкнутся одновременно. Кроме того, вам нужно было установить размер стека вручную - т.е. в системе с большим объемом оперативной памяти программа все равно была бы ограничена размером стека.

буфер фиксированного размера в стеке, достаточно большой для всех целей? Это не риторический вопрос...

Если вам нужен буфер фиксированного размера для всех целей, вы также можете поместить его в статическую/глобальную переменную или использовать память кучи.

person SigTerm    schedule 10.08.2010
comment
В качестве подделки смартпоинтеров, я думаю, alloca использовал машину времени, чтобы украсть идею. alloca относится к концу 1960-х годов, а интеллектуальные указатели - к 1986 году... В другом месте было сказано о безопасности потоков как о положительном результате распределения, которое статические/глобальные переменные не разделяют. Куча зависит от того, как вы ее используете, поэтому не обращайтесь к ней с помощью 900 символов. - person Heath Hunnicutt; 10.08.2010
comment
@Heath Hunnicutt: alloca использовала машину времени. Open Dynamics Engine не был написан в 60-х годах. - person SigTerm; 11.08.2010

Функция alloca() практически никогда не нужна; для целей распределения памяти вы можете использовать malloc()/free() в C (или один из наборов возможностей в C++) и добиться практически такого же практического эффекта. Преимущество этого заключается в том, что он лучше справляется с меньшим размером стека.

Однако я видел[1] одно законное (хотя и хакерское!) его использование: для обнаружения потенциального переполнения стека в Windows; если выделение (количества ненужного пространства, к которому вы хотели получить доступ) не удалось, вы выбыли, но у вас было достаточно места для изящного восстановления. Он был обернут в __try/__except, чтобы не зависал, и нуждался в дополнительных хитростях ассемблера, чтобы избежать проблем, вызванных gcc. Как я уже сказал, взлом. Но умный, это единственное правильное использование alloca(), которое я когда-либо видел.

Но не делай этого. Лучше написать код, чтобы не нужны были такие игры.


[1] Это было в Tcl 8.4 (и, возможно, в более ранних версиях Tcl). В более поздних версиях он был удален. Более поздние версии удалили его, потому что он был привередливым, очень сложным и вызывал серьезные проблемы. 8.6 использует бесстековую реализацию исполняющего движка вместо такого рода фанковости.

person Donal Fellows    schedule 10.08.2010
comment
FWIW: в Windows обычно есть защитная страница в конце стека, используемая для его динамического расширения. Как только предел стека будет достигнут и эта защитная страница сработает, вы получите исключение, но только один раз. Если они не сбросят защитную страницу после обнаружения конца стека, этот трюк сработает только один раз... В следующий раз программа будет немедленно завершена системой. - person Shog9; 16.08.2010
comment
@Shog: Интересно, хотя то, что нам больше не нужно; мы изменили способ работы нашего механизма реализации, чтобы больше не нуждаться в глубоком стеке C. :-) Я просто подумал, что это будет интересно людям как использование alloca, которое вообще не может быть продублировано malloc. - person Donal Fellows; 16.08.2010

Использование 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 *));

    /* ... */
}
person einpoklum    schedule 22.11.2016