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