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

问题描述 投票:18回答:7

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

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

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

c++ arrays dynamic-data
7个回答
21
投票

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

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


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


7
投票

请注意,该提案被拒绝,以下内容不再适用。但是,对于未来的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);
}

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 ++没有动态设置位置,只编译程序时只执行一次。为什么?它很简单:因为没有必要将可变大小的对象放到堆栈上,并且因为在分配/重新分配堆栈空间时使用它们会减慢所有程序的速度。

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


2
投票

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


2
投票

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

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


1
投票

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

FWIW,我读到Stroustrup说他不想要他们,但我不知道它在哪个采访中。


0
投票

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

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