为什么堆栈中没有可变大小的数组?

时间:2011-10-18 19:29:26

标签: c++ arrays dynamic-data

我真的不明白为什么我不能在堆栈上有一个可变大小的数组,所以像

foo(int n) {
   int a[n];
}

据我了解部分数据段的堆栈(-segment),因此它不是“常量”。

7 个答案:

答案 0 :(得分:21)

根据C ++标准,C ++中不允许使用

可变长度数组(VLA)
许多编译器(包括gcc)都支持它们作为编译器扩展,但重要的是要注意使用这种扩展的任何代码都是不可移植的。

C ++提供 std::vector 来实现与 VLA 类似的功能。


在C ++ 11中引入了可变长度数组 proposal ,但最终被删除了,因为它需要对C ++中的类型系统进行大量更改。能够在堆栈上创建小数组而不浪费空间或为未使用的元素调用构造函数的好处被认为对于C ++类型系统中的大变化而言不够重要。

答案 1 :(得分:6)

请注意,该提案遭到拒绝,以下情况不再适用。但是,对于未来的C ++版本,它可能会复活。

N3639中描述的VLA已经在布里斯托尔会议上被接受,并将成为C ++ 14的一部分,以及库对应部分“dynarray”。因此,使用支持C ++ 14的编译器,我们可以开始编写类似的东西:

void func(int n)
{
    int arr[n];
}

或者使用dynarray:

#include <dynarray>

void func(int n)
{
    std::dynarray<int> arr(n);
}

答案 2 :(得分:5)

我将尝试用一个例子解释这个:

说你有这个功能:

int myFunc() {
   int n = 16;
   int arr[n];
   int k = 1;
}

程序运行时,它会以这种方式将变量设置到堆栈中:

- n @relative addr 0
- arr[16] @relative addr 4
- k @relative addr 64
TOTAL SIZE: 68 bytes

假设我想将arr调整为4个元素。我要去做:

delete arr;
arr = new int[4];

现在:如果我以这种方式离开堆栈,堆栈将有未使用空间的漏洞。因此,最聪明的做法是将所有变量从堆栈中的一个位置移动到另一个位置并重新计算它们的位置。但是我们遗漏了一些东西:C ++没有动态设置位置,只编译程序时只执行一次。为什么?它很简单:因为没有必要将可变大小的对象放到堆栈上,并且因为在分配/重新分配堆栈空间时使用它们会减慢所有程序的速度。

这不是唯一的问题,还有另一个问题,甚至更大问题: 当你分配一个数组时,你决定它将占用多少空间,如果超过可用空间,编译器可以发出警告,相反,如果你让程序在你的堆栈上分配可变大小的数组,你就会打开安全漏洞,因为你使用这种方法的所有程序都容易受到堆栈溢出的影响。

答案 3 :(得分:2)

因为语言规范是这样说的。没有其他事情重要(由于不同的原因,解释细分是非常错误的。)

答案 4 :(得分:2)

简单回答:因为它没有在C ++标准中定义。

答案不是那么简单:因为在这种情况下,没有人支持C ++的一致行为。从标准POV没有堆栈,它可以完全不同地实现。 C99具有VLA,但它们似乎实现起来非常复杂,以至于gcc仅在4.6中完成了实现。我不认为很多人会想要为C ++提出一些建议并且看看编译器制造商多年来一直在努力。

答案 5 :(得分:1)

堆栈相当小,每个架构的大小可能会有很大差异。问题是,“过度分配”并导致seg故障或写入其他人拥有的内存相当容易。同时,问题的解决方案(例如vector)已经存在了很长时间。

FWIW,我读过Stroustrup说他不想他们,但我不知道它在哪个面试。

答案 6 :(得分:0)

因为在C ++中,静态数组需要一个静态常量大小,所以语言不允许这样做。请注意,C99支持堆栈中的vararrays,有些实现在C ++和扩展下支持它。