如何处理或避免C++; C++中,堆栈溢出通常会导致程序的不可恢复崩溃。对于需要真正健壮的程序来说,这是一种不可接受的行为,特别是因为堆栈大小是有限的。关于如何处理这个问题的几个问题
是否有一种方法可以通过通用技术防止堆栈溢出。(一个可扩展、健壮的解决方案,包括处理占用大量堆栈的外部库等)如何处理或避免C++; C++中,堆栈溢出通常会导致程序的不可恢复崩溃。对于需要真正健壮的程序来说,这是一种不可接受的行为,特别是因为堆栈大小是有限的。关于如何处理这个问题的几个问题,c++,error-handling,crash,stack-overflow,C++,Error Handling,Crash,Stack Overflow,是否有一种方法可以通过通用技术防止堆栈溢出。(一个可扩展、健壮的解决方案,包括处理占用大量堆栈的外部库等) 有没有办法在发生堆栈溢出时处理它们?最好是在有处理程序来处理这类问题之前,将堆栈展开 还有一些语言,它们的线程具有可扩展的堆栈。C++中有可能吗? < >对C++行为解决方案的任何其他有用的意见都将被理解。 处理堆栈溢出不是正确的解决方案,相反,您必须确保您的程序不会溢出堆栈 不要在堆栈上分配大变量(其中“大”取决于程序)。确保任何递归算法在已知最大深度后终止。如果递归算法可能会递归未知次
< >对C++行为解决方案的任何其他有用的意见都将被理解。 处理堆栈溢出不是正确的解决方案,相反,您必须确保您的程序不会溢出堆栈 不要在堆栈上分配大变量(其中“大”取决于程序)。确保任何递归算法在已知最大深度后终止。如果递归算法可能会递归未知次数或大量次,请自己管理递归(通过维护自己的动态分配堆栈)或将递归算法转换为等效的迭代算法 一个必须“非常健壮”的程序不会使用“消耗大量堆栈”的第三方或外部库
请注意,某些平台在堆栈溢出发生时会通知程序,并允许程序处理错误。例如,在Windows上,会引发异常。这个异常不是C++异常,但是它是异步异常。虽然C++异常只能由<代码>抛出语句抛出,但在执行程序时可能会在任何时候抛出异步异常。但这是意料之中的,因为堆栈溢出随时都可能发生:任何函数调用或堆栈分配都可能使堆栈溢出 问题是,堆栈溢出可能会导致异步异常被抛出,即使是预期不会抛出任何异常的代码(例如,在C++中标记为
noexcept
或throw()
的函数)。因此,即使您确实以某种方式处理了这个异常,您也无法知道您的程序处于安全状态。因此,处理异步异常的最佳方法是根本不处理它(*)。如果抛出一个,则表示程序包含错误
其他平台可能有类似的方法来“处理”堆栈溢出错误,但任何此类方法都可能遇到相同的问题:预期不会导致错误的代码可能会导致错误
(*)有一些非常罕见的例外情况。C++是一种功能强大的语言,伴随着这种能力,你可以向自己的脚开枪。我不知道有任何可移植的机制在堆栈溢出发生时检测和纠正/中止。当然,任何此类检测都是特定于实现的。例如,g++提供了
-fstack protector
来帮助监控堆栈使用情况
一般来说,您的最佳选择是主动避免基于堆栈的大型变量,并小心递归调用。您可以使用良好的编程实践来防止堆栈溢出,例如:
对于自动查找,您应该能够找到一些静态代码分析工具。Re:可扩展堆栈。您可以通过以下方式为自己提供更多的堆栈空间:
#include <iostream>
int main()
{
int sp=0;
// you probably want this a lot larger
int *mystack = new int[64*1024];
int *top = (mystack + 64*1024);
// Save SP and set SP to our newly created
// stack frame
__asm__ (
"mov %%esp,%%eax; mov %%ebx,%%esp":
"=a"(sp)
:"b"(top)
:
);
std::cout << "sp=" << sp << std::endl;
// call bad code here
// restore old SP so we can return to OS
__asm__(
"mov %%eax,%%esp":
:
"a"(sp)
:);
std::cout << "Done." << std::endl;
delete [] mystack;
return 0;
}
#包括
int main()
{
int sp=0;
//你可能想把这个放大很多
int*mystack=newint[64*1024];
int*top=(mystack+64*1024);
//保存SP并将SP设置为新创建的
//堆叠框架
__asm_uuuuuuuuuuuuuuuuuuuu(
“mov%%esp,%%eax;mov%%ebx,%%esp”:
“=a”(sp)
:“b”(顶部)
:
);
std::cout我认为这不管用。推送/pop esp比移动到寄存器更好,因为你不知道编译器是否会决定使用eax进行某些操作。给你:
您自己不会捕获异常\u堆栈\u溢出结构化异常,因为操作系统将捕获它(在Windows的情况下)
是的,您可以安全地从结构化异常(上面称为“异步”)中恢复,这与上面指出的不同。如果您不能,Windows将根本无法工作。PAGE_错误是从中恢复的结构化异常
我不太熟悉Linux和其他平台下的工作方式。标准甚至没有提到堆栈,您应该指定目标平台;有几个平台提供了拦截堆栈溢出的方法,甚至可以获得“堆栈溢出警报”当堆栈几乎耗尽时。就我个人而言,我发现堆栈溢出不是可以避免的,而是可以接受的