在过去的几年里,我不怎么使用C。当我今天读这个问题时,我遇到了一些我不熟悉的C语法。

显然,在C99中,以下语法是有效的:

void foo(int n) {
    int values[n]; //Declare a variable length array
}

这似乎是一个非常有用的功能。是否曾经讨论过将它添加到c++标准中,如果有,为什么省略了它?

一些潜在的原因:

编译器供应商难以实现 与标准的其他部分不兼容 功能可以用其他c++构造来模拟

c++标准规定数组大小必须是常量表达式(8.3.4.1)。

是的,当然我意识到在这个玩具示例中可以使用std::vector<int> values(m);,但这是从堆中分配内存而不是堆栈。如果我想要一个多维数组,比如:

void foo(int x, int y, int z) {
    int values[x][y][z]; // Declare a variable length array
}

矢量版本变得相当笨拙:

void foo(int x, int y, int z) {
    vector< vector< vector<int> > > values( /* Really painful expression here. */);
}

片、行和列也可能分布在整个内存中。

看看comp. stdc++上的讨论,很明显这个问题很有争议,争论双方都有一些重量级人物。当然,std::vector并不总是更好的解决方案。


当前回答

如果你愿意,你总是可以在运行时使用alloca()在堆栈上分配内存:

void foo (int n)
{
    int *values = (int *)alloca(sizeof(int) * n);
}

在堆栈上分配意味着当堆栈展开时它将自动被释放。

注意:正如在Mac OS X的alloca(3)手册中提到的,“alloca()函数依赖于机器和编译器;不鼓励使用它。”告诉你一声。

其他回答

为此使用std::vector。例如:

std::vector<int> values;
values.resize(n);

内存将在堆上分配,但这只会带来很小的性能缺陷。此外,不要在堆栈上分配大数据锁是明智的,因为它的大小相当有限。

VLAs是可变修改类型家族的一部分。 这类类型非常特殊,因为它们有运行时组件。

代码:

int A[n];

被编译器视为:

typedef int T[n];
T A;

注意,数组的运行时大小并不与变量A绑定,而是与变量的类型绑定。

没有什么可以阻止创建这种类型的新变量:

T B,C,D;

或者指针或数组

T *p, Z[10];

此外,指针允许创建动态存储的vla。

T *p = malloc(sizeof(T));
...
free(p);

这消除了一个流行的神话,即VLAs只能在堆栈上分配。

回到刚才的问题。

这个运行时组件不能很好地与类型演绎一起工作,而类型演绎是c++类型系统的基础之一。它不可能使用模板,演绎和重载。

c++类型系统是静态的,所有类型都必须在编译时完全定义或推导。 虚拟机类型只在程序执行时完成。 在已经非常复杂的c++中引入虚拟机类型的额外复杂性被认为是不合理的。主要是因为它们主要的实际应用 是自动vla (int A[n];),它们有std::vector的替代形式。

这有点令人遗憾,因为VM类型为处理多维数组的程序提供了非常优雅和高效的解决方案。

在C语言中,你可以简单地写:

void foo(int n, int A[n][n][n]) {
  for (int i = 0; i < n; ++i)
    for (int j = 0; j < n; ++j)
      for (int k = 0; k < n; ++k)
        A[i][j][k] = i * j * k;
}

...

int A[5][5][5], B[10][10][10];
foo(5, A);
foo(10, B);

现在尝试在c++中提供高效和优雅的解决方案。

似乎c++ 14中也可以使用:

https://en.wikipedia.org/wiki/C%2B%2B14#Runtime-sized_one_dimensional_arrays

更新:它没有进入c++ 14。

这样的数组是C99的一部分,但不是标准c++的一部分。正如其他人所说,向量总是一个更好的解决方案,这可能就是为什么可变大小数组不在c++标准中(或在提议的c++ 0x标准中)。

顺便说一句,关于“为什么”c++标准是这样的问题,可以去Usenet新闻组comp. stdc++。

这是考虑包含在c++ /1x中,但被放弃了(这是对我前面所说的更正)。

因为我们已经有了std::vector来填充这个角色,所以它在c++中就没有那么有用了。