为什么C++中的堆栈内存使用量是在编译时确定的?

问题描述 投票:0回答:1

在得知 VLA(可变长度数组)与 C++ 不兼容后,我第一次开始深入这个兔子洞。这是因为可变长度的数组在编译时不会有一个常量的大小,而 C++ 编译器需要它来计算程序将要分配的堆栈帧的大小运行。我知道这种在编译时知道这样的事情的愿望就是禁止 VLA 数组的原因(以及其他原因)。

但是,为什么要在编译时知道这样的事情(要分配的堆栈帧的大小)呢?为什么不能确定堆栈所需的所有内存,然后在运行时分配?我听说它解释说,在编译时确定堆栈帧的大小对于避免堆栈溢出异常很有用,因为您提前确切地知道给定函数调用需要多少内存。如果我们允许堆栈上有一个 VLA,其大小由运行时用户输入确定,他们可以输入一个巨大的数字,例如 100000000000,然后我们会得到堆栈溢出异常。禁止使用 VLA 可以让我们避免做类似的事情(或者至少我是这么理解的)。

这就是向我解释的,但我仍然不明白为什么这意味着一切都必须在编译时确定。例如,

alloca
可用于在运行时通过简单地移动堆栈指针来在堆栈上进行分配。为什么不能在运行时为函数中的每个新局部变量在内部完成此操作,以便我们可以拥有 VLA 而不是立即分配整个堆栈帧?我觉得答案应该是“很明显,所以你最终不会尝试分配比你拥有的更多的内存并导致堆栈溢出异常!”,但无论你采用什么技术,这不是一个风险吗?我可以尝试在运行时在堆上声明我的可变长度数组,但是如果我尝试分配比可用内存更多的内存怎么办?在这种情况下,我遇到了同样的问题,由于用户输入而占用了超出我所能承受的内存,并且在编译时计算程序的内存使用量无法拯救我。

那么,在编译时这样做仅仅是为了提高效率吗?如果是的话,是什么让它更有效率?难道我们只是提前计算需要为函数调用分配多少内存,而不是在运行时计算,从而在每次调用函数时节省几微秒的时间?

c++ stack-overflow compile-time variable-length-array alloca
1个回答
0
投票

我知道这种在编译时知道这样的事情的愿望就是禁止 VLA 数组的原因(以及其他原因)。

不禁止变长数组。 C++ 标准不要求实现支持它们。但是,C++ 标准允许扩展,并且 C++ 实现可能支持可变长度数组。

实现可变长度数组没有任何障碍,旧版本的 C 标准需要支持并且某些 C 和 C++ 实现支持它们这一事实就证明了这一点。

我听说它解释说,在编译时确定堆栈帧的大小对于避免堆栈溢出异常很有用,因为您提前确切地知道给定函数调用需要多少内存。

这是不正确的。一个函数可以调用其他函数,并且被调用的函数可以是递归的,并且可以通过编程方式调用。因此,虽然在编译期间可以知道函数的直接数据所需的堆栈内存量(在没有可变长度数组的情况下),但编译器并不总是知道函数所需的总内存。因此,不存在变长数组不足以以这种方式避免堆栈溢出。

C++ 中对可变长度数组的需求较少,因为 C++ 为动态数据结构提供了其他功能,因此我们可以推测 C++ 委员会尚未发现可变长度数组在 C++ 中具有足够的价值以需要支持它们。

© www.soinside.com 2019 - 2024. All rights reserved.