c++ - 为什么变长数组不是 C++ 标准的一部分?

标签 c++ arrays standards variable-length-array variable-length

最近几年我用 C 的次数不多。当我阅读 this question今天我遇到了一些我不熟悉的 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
}

vector版本变得相当笨拙:

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

切片、行和列也可能遍布整个内存。

查看 comp.std.c++ 的讨论很明显,这个问题在争论的双方都有一些非常重量级的名字是很有争议的。 std::vector 肯定不是很明显总是更好的解决方案。

最佳答案

(背景:我有一些实现 C 和 C++ 编译器的经验。)

C99 中的可变长度数组基本上是一个失误。为了支持 VLA,C99 不得不根据常识做出以下让步:

  • sizeof x不再总是编译时常量;编译器有时必须生成代码来评估 sizeof -运行时的表达式。

  • 允许二维 VLA ( int A[x][y] ) 需要一种新语法来声明以二维 VLA 作为参数的函数:void foo(int n, int A[][*]) .

  • 在 C++ 世界中不太重要,但对于 C 的嵌入式系统程序员目标受众来说却极其重要,声明 VLA 意味着占用任意大堆栈 block 。这是一个保证堆栈溢出和崩溃。 (任何时候你声明 int A[n] ,你都在隐含地断言你有 2GB 的堆栈空间。毕竟,如果你知道“n 在这里肯定小于 1000”,那么你只需声明 int A[1000] 。替换n 的 32 位整数 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 的类型,我们如何静态生成该代码?在编译时?

更糟糕的是,如果在运行时结果是 n1 != n2 怎么办? ,所以 !std::is_same<decltype(A1), decltype(A2)>() ?在这种情况下,调用 myfunc 甚至不应该编译,因为模板类型推导应该会失败!我们怎么可能在运行时模拟这种行为?

基本上,C++ 正朝着将越来越多的决策插入编译时的方向发展:模板代码生成,constexpr功能评价等。与此同时,C99 正忙于将传统的编译时决策(例如 sizeof)插入运行时。考虑到这一点,花费任何努力尝试将 C99 样式的 VLA 集成到 C++ 中真的有意义吗?

正如所有其他回答者已经指出的那样,当您真的想表达“我不知道我有多少 RAM可能需要。” C++ 提供了一个漂亮的异常处理模型来处理不可避免的情况,即您需要的 RAM 数量大于您拥有的 RAM 数量。但希望这个答案能让您很好地理解为什么 C99 风格的 VLA 适合 C++ — 甚至不适合 C99。 ;)


有关该主题的更多信息,请参阅 N3810 "Alternatives for Array Extensions" , Bjarne Stroustrup 2013 年 10 月关于 VLA 的论文。 Bjarne 的 POV 与我的非常不同; N3810 更侧重于为事物寻找良好的 C++ 风格语法,并且不鼓励在 C++ 中使用原始数组,而我更侧重于对元编程和类型系统的影响。我不知道他是否认为元编程/类型系统的含义已解决、可解决或仅仅是无趣。


一篇很好的博文是 "Legitimate Use of Variable Length Arrays" (克里斯·韦伦斯,2019-10-27)。

关于c++ - 为什么变长数组不是 C++ 标准的一部分?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58774398/

相关文章:

c++ - SIMD 指令缺少 OpenMP if 子句

C++:.bmp 到文件中的字节数组

javascript - 将对象插入 javascript 深拷贝还是浅拷贝中的数组?

arrays - 拆箱、(稀疏)矩阵和 haskell 向量库

javascript - 在单词数组中查找相似的单词

c - 'global' 和 'static global' 之间的区别

c++ - 通过重新解释转换创建无效引用

c++ - C++类中的 vector 参数

c++ - 此代码是否应该无法在 C++17 中编译?

c++ - vector<bool>::push_back GCC 3.4.3 中的错误?