(背景:我有一些实现C和C ++编译器的经验。)
C99中的可变长度数组基本上是一个错误的步骤。为了支持VLA,C99必须做出以下常识性让步:
sizeof x
不再总是编译时常量;编译器有时必须sizeof
在运行时生成代码以评估-expression。
允许使用二维VLA(int A[x][y]
),需要一种新的语法来声明将2D VLA作为参数的函数:void foo(int n, int A[][*])
。
在C ++领域中不太重要,但是对于C的嵌入式系统程序员的目标受众来说极为重要,声明VLA意味着砍断您的堆栈中任意大块。这是保证的堆栈溢出和崩溃。(无论何时声明int A[n]
,您都隐式断言您有2GB的可用堆栈空间。毕竟,如果您知道“ n
这里肯定小于1000”,则只需声明int A[1000]
。将32位整数替换n
为1000
允许值)您不知道程序的行为应该是什么。)
好的,现在让我们开始讨论C ++。在C ++中,我们在“类型系统”和“值系统”之间的区别与C89一样强,但是我们实际上已经开始以C所没有的方式来依赖它。例如:
template<typename T> struct S { ... };
int A[n];
S<decltype(A)> s; // equivalently, S<int[n]> s;
如果n
不是编译时常量(即,如果A
是可变修改的类型),那么到底是什么类型S
?是否也仅在运行时确定S
类型?
那这个呢:
template<typename T> bool myfunc(T& t1, T& t2) { ... };
int A1[n1], A2[n2];
myfunc(A1, A2);
编译器必须为的某些实例生成代码myfunc
。该代码应该是什么样的?如果我们不知道A1
编译时的类型,该如何静态生成该代码?
更糟糕的是,如果在运行时结果为that n1 != n2
,那该!std::is_same<decltype(A1), decltype(A2)>()
怎么办?在这种情况下,对的调用myfunc
甚至都不应编译,因为模板类型推导应该失败!我们如何在运行时模拟这种行为?
基本上,C ++朝着将越来越多的决策推向编译时的方向发展:模板代码生成,constexpr
函数评估等。同时,C99忙于将传统的编译时决策(例如sizeof
)推送到运行时。考虑到这一点,它真的甚至是有意义的花费任何力气试图以C99风格VLAS整合到C ++?
正如其他答复者已经指出的那样,当您真正想传达“我不知道我可能需要多少RAM”的想法时,C ++提供了很多堆分配机制(std::unique_ptr<int[]> A = new int[n];
或者std::vector<int> A(n);
很明显)。C ++提供了一个漂亮的异常处理模型来处理不可避免的情况,即所需的RAM数量大于所需的RAM数量。但是希望这个答案可以使您对C99样式的VLA为什么不适合C ++以及甚至不完全适合C99有所了解。;)
有关该主题的更多信息,请参见Bjarne Stroustrup在2013年10月发布的有关VLA的N3810“数组扩展的替代方案”。Bjarne的POV与我的有很大不同。N3810更着重于为事物找到良好的C ++ ish 语法,并阻止在C ++中使用原始数组,而我更着重于元编程和类型系统的含义。我不知道他是否认为元编程/类型系统的含义已解决,可解决或仅无趣。
一个很好的博客文章也提到了很多相同的问题,例如“合法使用可变长度数组”(Chris Wellons,2019-10-27)。