在过去的几年中,我很少使用C。今天,当我阅读此问题时,遇到了一些我不熟悉的C语法。
显然,在C99中,以下语法有效:
void foo(int n) {
int values[n]; //Declare a variable length array
}
这似乎是一个非常有用的功能。是否有关于将其添加到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
}
该vector
版本变得很笨拙:
void foo(int x, int y, int z) {
vector< vector< vector<int> > > values( /* Really painful expression here. */);
}
切片,行和列也可能会散布到整个内存中。
纵观讨论,comp.std.c++
很明显,这个问题在论证两边都带有一些非常重量级的名字,这引起了很大的争议。当然,std::vector
总是可以找到更好的解决方案。
最近在usenet中开始了对此的讨论:为什么C ++ 0x中没有VLA。
我同意那些似乎同意必须在堆栈上创建潜在的大型阵列(通常只有很少的可用空间)的做法不好的人。该参数是,如果你事先知道大小,则可以使用静态数组。而且,如果你事先不知道大小,你将编写不安全的代码。
C99 VLA可以带来一个小的好处,即能够创建小型数组而不会浪费空间或为未使用的元素调用构造函数,但是它们会给类型系统带来相当大的变化(你需要能够根据运行时值指定类型-这除了new
运算符类型说明符外,当前C ++中尚不存在该表达式,但对它们进行了特殊处理,因此运行时不会逃脱new
运算符的范围)。
你可以使用std::vector
,但它并不完全相同,因为它使用动态内存,并且使其使用自己的堆栈分配器并不是一件容易的事(对齐也是一个问题)。它也不能解决相同的问题,因为向量是可调整大小的容器,而VLA是固定大小的。在C ++动态阵列提议旨在介绍文库的基于溶液,作为替代基于VLA的语言。但是,据我所知,它不会成为C ++ 0x的一部分。
+1并被接受。不过,我有一个评论,我认为安全性论点有点弱,因为还有很多其他方法可以导致堆栈溢出。安全性参数可用于支持以下立场:您永远不要使用递归,并且应该分配堆中的所有对象。
因此,您说的是,因为还有其他导致堆栈溢出的方法,我们还是鼓励更多的方法吗?
@安德烈亚斯(Andreas)同意自己的弱点。但是对于递归而言,要消耗大量的调用才能耗尽堆栈,如果是这种情况,人们将使用迭代。就像Usenet线程上的一些人所说的那样,这并不是在所有情况下都反对VLA,因为有时您肯定会知道一个上限。但是在那些情况下,从我的角度来看,静态数组就足够了,因为无论如何它都不会浪费太多的空间(如果这样的话,那么您实际上必须问堆栈区域是否又足够大)。
还要看一下该线程中的Matt Austern的回答:由于C ++中类型匹配更严格,因此VLA的语言规范对于C ++可能要复杂得多(例如:C允许在C ++中将-分配
T(*)[]
给T(*)[N]
--这是不允许的,因为C ++不了解“类型兼容性”,它需要完全匹配),类型参数,异常,构造函数和析构函数以及其他内容。我不确定VLA的好处是否真的能付清所有工作。但是然后,我在现实生活中从未使用过VLA,因此我可能不知道它们的良好用例。@AHelps:也许对此最好的类型是一种行为类似
vector
但需要固定的LIFO使用模式并维护一个或多个每个线程静态分配的缓冲区的类型,该缓冲区通常根据该线程具有的最大总分配来确定大小。曾经使用过,但是可以明确地进行修剪。通常情况下,正常的“分配”只需要指针复制,指针与指针相减,整数比较和指针加法即可。取消分配将仅需要指针副本。不比VLA慢很多。