当您总是可以在堆栈上分配一个足够大以适应所有用途的固定大小的缓冲区时,为什么还要使用 alloca()?这不是一个修辞问题...
6 回答
如果缓冲区的大小在运行时变化,或者您只是有时需要它,这可能很有用:与每次调用中固定大小的缓冲区相比,这将使用更少的堆栈空间。特别是如果函数位于堆栈的高位或递归。
在什么情况下 alloca() 有用?
我唯一一次看到使用 alloca 是在 Open Dynamics Engine 中。AFAIK 他们正在用它分配巨大的矩阵(因此编译的程序可能需要 100MB 堆栈),当函数返回时自动释放这些矩阵(对我来说就像智能指针剽窃)。这是很久以前的事了。
尽管它可能比 new/malloc 快得多,但我仍然认为这是一个坏主意。当场景变得太复杂而无法处理时,程序可能会因堆栈溢出而崩溃(即误导),而不是礼貌地用完 RAM 。不是一个好的行为,IMO,特别是对于物理引擎,你可以很容易地期望有人将几千块砖扔到场景中,看看当它们同时碰撞时会发生什么。另外,您必须手动设置堆栈大小 - 即在具有更多 RAM 的系统上,程序仍将受到堆栈大小的限制。
堆栈上的固定大小缓冲区足够大以适应所有用途?这不是一个修辞问题...
如果您需要所有用途的固定大小缓冲区,那么您也可以将其放入静态/全局变量或使用堆内存。
alloca()
几乎从不需要该功能;出于内存分配目的,您可以在 C 中使用malloc()
/ free()
(或 C++ 中的可能性集合之一)并实现几乎相同的实际效果。这具有更好地应对较小堆栈大小的优势。
但是我已经看到[1]一个合法的(如果 hacky !)使用它:用于检测 Windows 上的潜在堆栈溢出;如果分配(您想要访问的 slop 空间量)失败,您就退出了,但有足够的空间来优雅地恢复。它被包裹在__try
/__except
中,因此它不会崩溃,并且需要额外的汇编程序技巧来避免 gcc 引起的麻烦。正如我所说,一个黑客。但是一个聪明的,是alloca()
我见过的唯一有效的用途。
但不要那样做。最好编写代码以不需要此类游戏。
[1]它在 Tcl 8.4(可能还有早期版本的 Tcl)中。它在以后的版本中被删除。后来的版本删除了它,因为它很挑剔,非常棘手且令人深感不安。8.6 使用执行引擎的无堆栈实现,而不是那种时髦。
如果无法知道编译时可能需要的最大大小,您可能想要使用它。
你是否应该是另一个问题- 它不是标准的,并且没有办法判断它是否会导致堆栈溢出。
从不 - 它不是 C++ 的一部分,在 C 中没有用。但是,您不能分配“堆栈上的静态缓冲区” - 静态缓冲区是在编译时分配的,而不是在堆栈上。
alloca() 的要点当然是它不是固定大小的,它在堆栈上,并且在函数退出时会自动释放。C++ 和 C 都有更好的机制来处理这个问题。
当您无法可靠地使用(或在 C++ 或其他内存分配器中)或根本无法使用时,使用alloca()
可能是合理的,但您可以假设堆栈上有更多可用空间 - 也就是说,当您真的无能为力时.malloc()
new
例如,在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 *));
/* ... */
}