在C++中使用递归的主要准则是什么?
What are the main guidelines for using recursion in C++?
作为C++相对较新的,我想知道在使用递归时是否有具体的事情需要考虑,因为与Python,Java和/或函数式语言等语言相比,该语言的特殊性和低级性。
另外,我想知道各种编译器之间在如何处理递归(尤其是关于尾递归)方面是否存在许多差异。我目前在CodeBlocks和VS2010上与gcc合作。
C++中的递归应该是绑定的,而不是下降得很深——尤其是当你的实现能够创建重要的堆栈分配时。如果您的程序不满足这些要求,则应采用另一种方法(例如迭代)。
每个函数调用都需要一些堆栈存储,并且函数参数也需要堆栈存储。您获得多少堆栈存储取决于您的实现/环境。现代桌面系统通常不会给您超过几 MB。其他实现将为您提供更少的资源。
如果您的调用超出了线程堆栈的边界,则会出现堆栈溢出。
有一些优化可以消除递归函数中的嵌套调用,但您的实现不应依赖于此行为,因为它不安全(例如,在更新编译器、更改构建设置或随着代码库的发展后,可能不再执行优化)。
您应该知道,大多数编译器/执行环境决定某些特定的堆栈大小 - 1MB 到 8MB 是非常典型的 - 根据我的经验C++运行时并不是为了动态增加它而设计的。 某些系统为程序代码启动的线程提供的堆栈可能比为操作系统启动的主线程提供的堆栈更少。 例如,在 Linux 上,您的 shell 可能允许您在运行应用程序之前使用 ulimit
来设置堆栈大小,但某些系统需要权限才能增加大小或可能有内核限制。
许多C++编译器在提供尾递归函数优化方面做得很好,因此内存使用量不会随着递归的深度而增长,但是当失败时,您可能会达到上述堆栈大小限制。
对于我使用的大多数语言(python,ruby,C,pascal等),这是非常典型的,并且C++对象往往非常小且内存效率高,因此您可能会比python中的等效数据和堆栈大小做得更好。
尽管如此,你还是提到了"函数式语言",它是如此开放,有些是如此"实验性",我敢打赌,有些人实际上为递归动态分配"堆"内存,并且可以远远超出C++实现倾向于支持的范围。 某些在虚拟机上运行/解释字节代码的语言也可能这样做。
我会注意递归函数中使用的任何指针、指针到指针等,以防您发现自己站在自己的尾巴上。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- C++避免重复声明的语法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- C++中名称篡改的目的是什么
- 在 c++ 中拥有一组结构的正确方法是什么?
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 是什么阻止DOMTimerCoordinator::NextID进入无休止的循环
- 派生类销毁的最佳实践是什么
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- 通过JNI传递数据数组的最快方法是什么
- "using namespace std;"在C++的作用是什么?
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 文件系统:复制功能的速度秘诀是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么