在递归C++函数中捕获"堆栈溢出"异常

oma*_*mar 10 c++ recursion exception-handling exception

是否有可能stack overflow exception在递归C++函数中捕获?如果是这样,怎么样?

那么在这种情况下会发生什么

void doWork()
{

     try() {

     doWork();    
     }


     catch( ... )  {

     doWork();    
     }
}  
Run Code Online (Sandbox Code Playgroud)

我不是在寻找特定操作系统的答案.总的来说

Cha*_*via 11

实际上没有可移植的方法.失控的递归函数在尝试将堆栈帧分配到堆栈地址空间之外时,通常会导致无效的内存访问.这通常会使程序崩溃,因为操作系统会出现分段错误/访问冲突.换句话说,它不会抛出可以通过语言以标准方式处理的c ++异常.


Jer*_*ner 11

它本身并不例外,但如果您只想将堆栈使用量限制为固定数量,则可以执行以下操作:

#include <stdio.h>

// These will be set at the top of main()
static char * _topOfStack;
static int _maxAllowedStackUsage;

int GetCurrentStackSize()
{
   char localVar;
   int curStackSize = (&localVar)-_topOfStack;
   if (curStackSize < 0) curStackSize = -curStackSize;  // in case the stack is growing down
   return curStackSize;
}

void MyRecursiveFunction()
{
   int curStackSize = GetCurrentStackSize();
   printf("MyRecursiveFunction:  curStackSize=%i\n", curStackSize);

   if (curStackSize < _maxAllowedStackUsage) MyRecursiveFunction();
   else
   {
      printf("    Can't recurse any more, the stack is too big!\n");
   }
}

int main(int, char **)
{
   char topOfStack;
   _topOfStack = &topOfStack;
   _maxAllowedStackUsage = 4096;  // or whatever amount you feel comfortable allowing

   MyRecursiveFunction();
   return 0;
}
Run Code Online (Sandbox Code Playgroud)


Max*_*ert 7

没有便携的方式.但是,有一些非便携式解决方案.

首先,正如其他人所说,Windows提供了一个非标准__try__except框架所谓结构化Exeption处理(您的具体答案是知识库).

其次,alloca- 如果实现正确 - 可以告诉你堆栈是否即将溢出:

bool probe_stack(size_t needed_stack_frame_size)
{
    return NULL != alloca(needed_stack_frame_size);
};
Run Code Online (Sandbox Code Playgroud)

我喜欢这种方法,因为在最后probe_stack,alloca分配的内存被释放并可供您使用.不幸的是,只有少数操作系统alloca正确实现. alloca永远不会NULL在大多数操作系统上返回,让你发现堆栈已经溢出一个壮观的崩溃.

第三,类UNIX系统通常有一个标题,调用ucontext.h函数来设置堆栈的大小(实际上,将多个堆栈链接在一起).您可以跟踪堆栈中的位置,并确定是否即将溢出.Windows具有类似的能力a la CreateFiber.


从Windows 8开始,Windows具有专门针对此功能(GetCurrentThreadStackLimits)


asv*_*kau 6

即使你可以像在Windows中那样非移植地执行此操作,它仍然是一个非常糟糕的主意.最好的策略是首先不要溢出堆栈.如果您需要从一些您无法控制的代码中隔离,请在不同的进程中运行该代码,并且可以检测它何时崩溃.但是你不想在你自己的过程中做那种事情,因为你不知道违规代码将要做什么样的令人讨厌的腐败状态,这将使你不稳定.

微软的Raymond Chen 发表了一篇有趣的,有点相关的博客文章,讲述为什么你不应该尝试在Windows上的用户模式应用程序中检查有效指针.


San*_*nto 0

大多数现代操作系统总是这样做。如果您想自己执行此操作,则必须知道堆栈的最大“安全”地址(或者同样进行一些数学计算以确定可以安全调用该函数的次数),但这可能会变得非常棘手如果您不自己管理调用堆栈,因为操作系统通常(出于充分的理由)向您隐藏这一点。

如果您在内核空间中编程,这会变得更加容易,但我仍然质疑您为什么这样做。如果出现堆栈溢出,可能是因为算法决策错误或代码中存在错误。

编辑:刚刚意识到您想要“捕获所产生的异常”。我认为我的答案根本不直接回答这个问题(这个例外是否存在?我会认为这是一个巨大的失败),但我将把它留给洞察力。如果您希望将其删除,请在评论中告诉我,我会这样做。