如何在 C++ 中处理或避免堆栈溢出

2022-01-12 00:00:00 error-handling stack-overflow crash c++

在 C++ 中,堆栈溢出通常会导致程序不可恢复的崩溃.对于需要真正健壮的程序,这是一种不可接受的行为,特别是因为堆栈大小是有限的.关于如何处理问题的几个问题.

In C++ a stack overflow usually leads to an unrecoverable crash of the program. For programs that need to be really robust, this is an unacceptable behaviour, particularly because stack size is limited. A few questions about how to handle the problem.

  1. 有没有办法通过通用技术来防止堆栈溢出.(一种可扩展、强大的解决方案,包括处理消耗大量堆栈的外部库等)

  1. Is there a way to prevent stack overflow by a general technique. (A scalable, robust solution, that includes dealing with external libraries eating a lot of stack, etc.)

如果发生堆栈溢出,有没有办法处理它们?最好,堆栈会展开,直到有处理程序来处理这种问题.

Is there a way to handle stack overflows in case they occur? Preferably, the stack gets unwound until there's a handler to deal with that kinda issue.

有些语言的线程具有可扩展的堆栈.类似的东西在 C++ 中可能吗?

There are languages out there, that have threads with expandable stacks. Is something like that possible in C++?

如果对 C++ 行为的解决方案有任何其他有用的意见,我们将不胜感激.

Any other helpful comments on the solution of the C++ behaviour would be appreciated.

推荐答案

处理堆栈溢出不是正确的解决方案,相反,您必须确保您的程序不会溢出堆栈.

Handling a stack overflow is not the right solution, instead, you must ensure that your program does not overflow the stack.

不要在堆栈上分配大变量(其中大"取决于程序).确保任何递归算法在已知最大深度后终止.如果递归算法可能会递归未知次数或大量次数,要么自己管理递归(通过维护自己的动态分配的堆栈),要么将递归算法转换为等效的迭代算法

Do not allocate large variables on the stack (where what is "large" depends on the program). Ensure that any recursive algorithm terminates after a known maximum depth. If a recursive algorithm may recurse an unknown number of times or a large number of times, either manage the recursion yourself (by maintaining your own dynamically allocated stack) or transform the recursive algorithm into an equivalent iterative algorithm

必须真正健壮"的程序不会使用吃掉大量堆栈"的第三方或外部库.

A program that must be "really robust" will not use third-party or external libraries that "eat a lot of stack."

请注意,某些平台会在发生堆栈溢出时通知程序并允许程序处理错误.例如,在 Windows 上,会引发异常.此异常不是 C++ 异常,但它是异步异常.而 C++ 异常只能由 throw 语句引发,而异步异常可能在程序执行期间的任何时间引发.不过这是意料之中的,因为堆栈溢出随时可能发生:任何函数调用或堆栈分配都可能溢出堆栈.

Note that some platforms do notify a program when a stack overflow occurs and allow the program to handle the error. On Windows, for example, an exception is thrown. This exception is not a C++ exception, though, it is an asynchronous exception. Whereas a C++ exception can only be thrown by a throw statement, an asynchronous exception may be thrown at any time during the execution of a program. This is expected, though, because a stack overflow can occur at any time: any function call or stack allocation may overflow the stack.

问题是堆栈溢出可能导致异步异常被抛出,即使是从不期望抛出任何异常的代码(例如,从标记为 noexceptthrow() 在 C++ 中).因此,即使您确实以某种方式处理了此异常,您也无法知道您的程序处于安全状态.因此,处理异步异常的最好方法是根本不处理它(*).如果抛出一个,则意味着程序包含错误.

The problem is that a stack overflow may cause an asynchronous exception to be thrown even from code that is not expected to throw any exceptions (e.g., from functions marked noexcept or throw() in C++). So, even if you do handle this exception somehow, you have no way of knowing that your program is in a safe state. Therefore, the best way to handle an asynchronous exception is not to handle it at all(*). If one is thrown, it means the program contains a bug.

其他平台可能有类似的方法来处理"堆栈溢出错误,但任何此类方法都可能遇到相同的问题:预期不会导致错误的代码可能会导致错误.

Other platforms may have similar methods for "handling" a stack overflow error, but any such methods are likely to suffer from the same problem: code that is expected not to cause an error may cause an error.

(*) 有一些非常罕见的例外情况.

相关文章