gpt4 book ai didi

c++ - 在 catch block 中抛出异常时打印回溯

转载 作者:行者123 更新时间:2023-11-30 05:19:33 29 4
gpt4 key购买 nike

我想打印异常的回溯(此时的状态是抛出的地方),但是在 catch block 中。

我也只是针对 gcc,但希望将不可移植的代码保持在最低限度(我知道我在示例中显示的堆栈打印代码是不可移植的)。

据我目前的理解,在 catch block 中,堆栈已经部分展开,因此不再需要读取。公平地说,如果没有创建局部变量并且没有完成任何方法调用,它应该仍然存在(在内存中),但我不确定尝试以这种方式读取它有多安全。

我还注意到,如果我注册了一个终止方法(通过 std::set_terminate)并且没有 catch block ,那么处理程序可以使用未处理的异常被抛出点的完整堆栈。我猜这是因为它完全展开了,但堆栈中的原始值没有被覆盖(很可能终止处理程序以某种方式具有独立的调用堆栈)。

我在 gcc 下测试过这个:

#include <cstdlib>
#include <iostream>
#include <stdexcept>

#include <execinfo.h>

using namespace std;

void handler()
{
void *trace_elems[20];
int trace_elem_count(backtrace(trace_elems, 20));
char **stack_syms(backtrace_symbols(trace_elems, trace_elem_count));
for(int i=0 ; i != trace_elem_count; ++i)
{
cout << stack_syms[i] << "\n";
}
free(stack_syms);

exit(1);
}

void level3() { throw std::runtime_error("oops"); }
void level2() { level3(); }
void level1() { level2(); }

如果我这样使用它,异常回溯就会丢失(只有 main 和 handler 在调用堆栈中):

void main()
{
try { level1(); }
catch(...) { handler();}
}

但是如果我这样调用它,则会打印异常抛出点的回溯:

void main()
{
std::set_terminate(handler);
level1();
}

关于我的用例的一些上下文:我有两个正在运行的进程,一个生成请求,另一个处理它们。这些请求的执行有时会导致异常。那时回溯对于找出它失败的原因很有用(what() 通常没有足够的信息),但我不能让异常到达 main,因为两个进程都需要继续工作。我只需要打印回溯并返回一条表示执行失败的消息。

编辑: 针对此问题提出的一个常见解决方案是拥有一个基异常类,该异常类在构造时捕获调用堆栈,并可在以后打印出来。这当然是一种可能的解决方案(如果找不到更好的解决方案,我可能不得不求助于此)。

我目前正在避免它,因为:

  1. 它增加了一些(相当大的)开销来在我抛出异常时捕获调用堆栈
  2. 在不得不放弃并打印堆栈跟踪之前,我实际上可以处理异常的情况比例相对较高。

最佳答案

您可以创建一个自定义异常类,在其构造函数中调用 backtrace 并将缓冲区存储在自身中。

当被捕获时,此类异常将具有打印跟踪所需的数据。事实上,处理程序很可能是异常的成员函数。请注意,跟踪将包括对异常构造函数的额外调用。

只要您只抛出自定义异常或从中派生的异常,这就有效。

关于c++ - 在 catch block 中抛出异常时打印回溯,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41059294/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com