在过去的几年里,我不怎么使用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并不总是更好的解决方案。
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++中提供高效和优雅的解决方案。
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++中提供高效和优雅的解决方案。