为啥 C++ 不支持堆栈上的动态数组? [关闭]
Posted
技术标签:
【中文标题】为啥 C++ 不支持堆栈上的动态数组? [关闭]【英文标题】:Why doesn't C++ support dynamic arrays on the stack? [closed]为什么 C++ 不支持堆栈上的动态数组? [关闭] 【发布时间】:2011-11-19 12:09:39 【问题描述】:在 C99 中这是合法的:
void f(size_t sz)
char arr[sz];
// ...
但是,这个 - 动态大小的堆栈数组 - 在 C++ 中已被删除,并且在 C++11 中没有看到返回。
AFAIK C++ 是在考虑 C 兼容性的情况下制作的,所以我想肯定有一些很好的论据不包括这个有用的特性,对吧?
我能想到的只有这个:
优点
通过允许需要在堆栈上的更智能的数组大小(临时缓冲区?)来节省内存。 更少的“智能指针”(或更糟糕的是,手动引入错误delete []
's)和缓慢的堆分配。
与 C99 的兼容性。
缺点
允许人们轻松地在堆栈上分配太大的数组,从而导致难以调试的堆栈溢出。 编译器编写者更复杂。那么,为什么他们在导入其他 C99 功能时没有包含它?
为了防止这被认为是“主观的”或“不具建设性的”,我正在寻找委员会成员的报价或讨论此事的链接——当然还有加分,以便快速总结。
与其将其视为小马与仓鼠的讨论,不如将其视为一个历史问题,仅仅是对所考虑的优点和缺点的兴趣(如果有的话)。
编辑:正如 James McNellis 在下面的 cmets 中指出的那样,C++ 存在于 C99 标准化可变长度数组之前。您可能会将我的问题解读为:“他们为什么没有也不会添加它?”。
【问题讨论】:
它没有被“删除”,因为它从来都不是 C++ 的一部分。 顺便说一句,在我看来,这似乎是一个有明确答案的明确问题。这似乎不是主观的,虽然“丢弃”这个词有点负荷并且不完全准确,但我认为这是一个小问题。 我有点惊讶人们如此喜欢结束“为什么?”作为“主观”的问题。恕我直言,*** 上的许多 最佳 问题确实是“为什么”问题。(参见 here。)仅仅因为多人可以对答案有多种猜测并不意味着没有正确答案。我认为人们应该冷静下来,让这样的问题继续下去,而不是仅仅因为他们想不出一个客观的答案而当场关闭它们。 :\ 结束问题的原因是为了保持 SO 上内容的质量。在剩下的所有蹩脚问题中,this 问题是如何引起如此多争议的?让它保持打开状态;很有帮助也很有趣。 这不是一个糟糕的问题,因为它是主观的,它很糟糕,因为它是重复的。 :-) 【参考方案1】:我认为,这是因为 C++ 提供了卓越的解决方案:std::vector<T>
和 std::array<T,N>
(C++11);尽管后者本身不是动态的,但它优于原始数组。无论您传递向量或数组的哪个函数,您始终可以知道大小。
由于 C 无法提供这些解决方案,C99 提出了可变长度数组 (VLA)。它和普通数组有同样的问题:它在传递给函数时衰减成一个指针,你不再知道数组的大小。
正如 Florian Weimer 在 comp.std.c++
向 here 询问的那样,如果 C++0x 允许 VLA,那么下面的代码是什么意思?
int vla[n]; //n is known at runtime!
std::vector<decltype(vla)> v; //what does this mean?
当向量模板的类型参数取决于运行时已知的n
时,编译器如何在编译时实例化向量模板?
【讨论】:
如果你 -1 某事,只是礼貌地说出原因。 @Downvoter:请说明原因,以便其他人和我知道为什么这个答案很愚蠢;以及如何改进。 这是一个有效的答案,如果您不同意,请不要盲目投反对票,而是在 cmets 中说。请阅读否决按钮的工具提示:“此答案无用”。我不同意这个特定问题。 我没有 -1'ed,但我不同意“C++ 解决方案优越”:也许它们在很多情况下。但是在仔细分析了我最近必须编写的一段代码之后,唯一明智的选择是静态向量或 gcc 的 VLA 扩展,以避免过于频繁的堆分配。我选择向量是为了可移植性,但这给我留下了一个非线程安全的函数(它正在等待“thread_local”实现)。在这种情况下,不需要知道函数外部的大小,并且 VLA 优于 std::array (顺便说一句,我不明白为什么 std::array 比 VLA 慢)。 @Nawaz:std::vector<T>
初始化其元素,这在某些情况下可能会导致不可接受的性能损失。 decltype
问题是一个红鲱鱼;编译器可以简单地禁止它,Objective-C++ 编译器也是如此:Variably modified type 'decltype(a)' (aka 'int [n]') cannot be used as a template argument
。【参考方案2】:
此功能在很大程度上复制了std::vector
的功能,只是它消耗的资源更有限(堆栈空间与堆空间)。因此,在 C++ 中,从语义上讲,实际上不需要它。
有人可能会争辩说,堆栈分配可以提高效率(尤其是在面对多线程时);但是,这也可以在 C++ 中使用自定义分配器在堆栈或堆上构建私有内存池来实现。这再次比将内存放在堆栈上更灵活,实际上您可以创建一个自定义分配器,该分配器很容易从堆栈内存缓冲区中分割出块。它与动态数组语义并不完全相同,但自定义分配器和 STL 容器的存在涵盖了您想要堆栈分配的大多数用例。
【讨论】:
是否有过这样的讨论?我想到的一件事是堆栈空间自动是线程本地的,这可能是一件非常有用的事情,因为与在许多实现上分配堆空间相比,它使得分配堆栈空间非常快。但我可以理解这一事实是否被考虑并发现不令人信服。我只是好奇。 @bdolan:堆栈空间是 O(1) 速度分配,非常适合文件名(大约 256 个字符 max)之类的东西。堆分配相对要慢得多,使用小字符串的应用程序通常可以通过使用前者而不是后者而受益匪浅。所以我个人不相信在 C++ 中没有“需要”它。 (否则,为什么编译器会如此频繁地实现_alloca
?)
我不知道这是否真的在标准化过程中讨论过,但排除它似乎是一个合理的理由。是的,本地分配的效率可能会稍微高一些,但是很多 malloc 实现无论如何都有线程本地池,而且对于更大的分配,构建成本无论如何都超过分配的成本。
@Mehrdad, std::string
实现通常在对象中分配了小字符串...
@Mehrdad:Visual C++ 2010 std::string
实现使用小字符串优化。以上是关于为啥 C++ 不支持堆栈上的动态数组? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章