为什么C++不支持堆栈上的动态数组?

orl*_*rlp 30 c++ standards stack dynamic-arrays

在C99这是合法的:

void f(size_t sz) {
    char arr[sz];
    // ...
}
Run Code Online (Sandbox Code Playgroud)

但是,这个 - 动态大小的堆栈数组 - 已经在C++中被删除了,而没有在C++ 11中看到返回.

AFAIK C++是在考虑到C兼容性的情况下制作的,所以我想知道必须有一些非常好的论据,不包括这个有用的功能,对吗?

我能想到的就是:

优点

  • 允许更智能的阵列大小需要在堆栈上(临时缓冲区?),从而节省内存.
  • 减少"智能指针"(或更糟糕的是,手动错误引入delete [])和慢堆分配.
  • 与C99的兼容性.

缺点

  • 允许人们在堆栈上轻松分配过大的数组,从而产生难以调试的堆栈溢出.
  • 编译器编写者更复杂.

那么,为什么他们在导入其他C99功能时没有包含它?


为了防止这种情况被关闭为"主观"或"不具有建设性",我正在寻找来自委员会成员的引用或者讨论谈论此事的讨论的链接 - 当然还有快速的SO综述的奖励积分.

而不是将其视为小马与仓鼠的讨论,将其视为一个历史问题,仅仅关注所考虑的优势和劣势(如果有的话).


编辑:正如James McNellis在下面的评论中所指出的,C++标准化可变长度数组之前存在C++.你可能会把我的问题读作:" 为什么没有,他们不会添加它? ".

Naw*_*waz 19

我认为,这是因为C++提供了卓越的解决方案:std::vector<T>std::array<T,N>(C++ 11); 虽然后者不是动态的,但它优于原始数组.无论您通过向量或数组传递哪种函数,都可以随时了解大小.

由于C不能提供这些解决方案,C99提出了可变长度阵列(VLA).它与常规数组有同样的问题:它会在将其传递给函数时衰减为指针,并且您不再知道数组的大小.

正如Florian Weimer 在此comp.std.c++那样,如果C++ 0x允许VLA,那么下面的代码意味着什么?

int vla[n]; //n is known at runtime!
std::vector<decltype(vla)> v; //what does this mean?
Run Code Online (Sandbox Code Playgroud)

当编译器的类型参数依赖于运行时已知的时,编译器如何在编译时实例化矢量模板?n

  • 如果你-1某事,说出原因是唯一的礼貌. (4认同)
  • @Downvoter:请说明原因让别人和我知道为什么这个答案很傻; 以及如何改进. (3认同)
  • 这是一个有效的答案,如果你不同意,不要盲目地投票,而是在评论中说.请阅读downvote按钮的工具提示:_"这个答案没用"_.我在这个特定问题上不同意这一点. (3认同)
  • 我没有做过,但我不同意"C++解决方案是优越的":也许他们处于很多环境中.但在仔细分析了我最近编写的一段代码之后,唯一明智的选择是静态向量或gcc的VLA扩展,以避免过于频繁的堆分配.我选择了vector来实现可移植性,但这给我留下了一个非线程安全的函数(它正在等待"thread_local"实现).在这种情况下,知道函数外部的大小是不可能的,并且VLA _was_优于std :: array(顺便说一下,我无法理解为什么std :: array比VLA慢得多). (3认同)
  • @Nawaz:`std :: vector <T>`初始化它的元素,在某些情况下可能会导致不可接受的性能损失.'decltype`问题是一个红鲱鱼; 编译器可以简单地禁止它,就像Objective-C++编译器一样:`可变修改类型'decltype(a)'(又名'int [n]')不能用作模板参数`. (3认同)
  • 你说C++提供了优秀的解决方案,但是std :: vector存储在堆上,std :: array不是动态的.我没看到他们是如何优越的.说实话,这是在C++发明之后添加到C标准中的,因此它从未被包含在内.它也更难实现,因为堆栈上的大多数变量通常被称为堆栈+4或堆栈+8或任何常量.因此,您必须为每个堆栈变量保留一个偏移量变量. (2认同)