以下程序将调用fun2 ^ (MAXD + 1) 次。不过,最大递归深度永远不应该超过 MAXD(如果我的想法是正确的)。因此,编译可能需要一些时间,但它不应该占用我的内存。
#include<iostream>
const int MAXD = 20;
constexpr int fun(int x, int depth=0){
return depth == MAXD ? x : fun(fun(x + 1, depth + 1) + 1, depth + 1);
}
int main(){
constexpr int i = fun(1);
std::cout << i << std::endl;
}
问题是,它确实会吃掉我的内存。当我将 MAXD 调至 30 时,我的笔记本电脑在 GCC 4.7.2 快速分配 3 GB 左右后开始交换。我还没有尝试过 clang 3.1,因为我现在无法访问它。
我唯一的猜测是,这与 GCC 试图过于聪明并记住函数调用有关,就像它对模板所做的那样。如果是这样,那么他们对记忆量(例如 MRU 缓存表的大小或其他内容)没有限制,这难道不奇怪吗?我还没有找到禁用它的开关。
我为什么要这样做?
我正在考虑制作一个高级编译时库,比如遗传编程之类的。由于编译器没有编译时尾调用优化,我担心任何循环都需要递归,并且(即使我打开最大递归深度参数,这看起来有点难看)会快速分配我所有的 RAM 并填充它带有毫无意义的堆栈帧。因此,我想出了上述解决方案,可以在没有深堆栈的情况下获得任意多个函数调用。这样的功能可用于折叠/循环或蹦床。
编辑:
现在我已经在 clang 3.1 中尝试过了,它根本不会泄漏内存,无论我让它工作多长时间(即我使 MAXD 有多高)。正如预期的那样,CPU 使用率几乎为 100%,内存使用率几乎为 0%。也许这只是 GCC 中的一个错误。
这可能不是关于 constexpr 的权威文档,但它是从gcc constexpr 维基。 http://gcc.gnu.org/wiki/Constexpr
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf
...它说...
我们(仍然)禁止常量表达式中的所有形式的递归。
这并不是严格必要的,因为实施限制
常量表达式求值中的递归深度将使我们免于
编译器永远递归的可能性。然而,直到我们
看到一个令人信服的递归用例,我们不建议允许它。
所以,我希望您会遇到语言边界以及 gcc 选择实现 constexpr 的方式(可能尝试内联生成整个函数,然后评估/执行它)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)