之前已经问过这个问题,并且有特定于Windows的答案,但没有令人满意的gcc答案。我可以使用set_terminate()
设置一个函数,该函数将在引发未处理的异常时调用(代替terminate()
)。我知道如何使用backtrace库从程序中的给定点生成堆栈跟踪。但是,这在调用我的终止替换时无济于事,因为那时候堆栈已经退绕。
但是,如果我只允许程序abort()
,它将生成一个核心转储,其中包含从引发异常时起的完整堆栈信息。信息就在那里了-但是有没有一种编程的方式来获取它,例如可以将其记录下来,而不必检查核心文件?
最佳答案
编辑答案:
您可以使用std::set_terminate
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <execinfo.h>
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 )
{
std::cout << stack_syms[i] << "\n";
}
free( stack_syms );
exit(1);
}
int foo()
{
throw std::runtime_error( "hello" );
}
void bar()
{
foo();
}
void baz()
{
bar();
}
int
main()
{
std::set_terminate( handler );
baz();
}
给出以下输出:
samm@macmini ~> ./a.out
./a.out [0x10000d20]
/usr/lib/libstdc++.so.6 [0xf9bb8c8]
/usr/lib/libstdc++.so.6 [0xf9bb90c]
/usr/lib/libstdc++.so.6 [0xf9bbaa0]
./a.out [0x10000c18]
./a.out [0x10000c70]
./a.out [0x10000ca0]
./a.out [0x10000cdc]
/lib/libc.so.6 [0xfe4dd80]
/lib/libc.so.6 [0xfe4dfc0]
samjmill@bgqfen4 ~>
假设您的二进制文件中有调试符号,则可以使用addr2line构造一个更漂亮的堆栈跟踪postmortem
samm@macmini ~> addr2line 0x10000c18
/home/samm/foo.cc:23
samm@macmini ~>
原始答案如下
我过去使用boost::error_info完成此操作,以使用
backtrace
从execinfo.h
将堆栈跟踪注入(inject)到抛出的异常中。typedef boost::error_info<struct tag_stack_str,std::string> stack_info;
然后在捕获异常时,您可以执行
} catch ( const std::exception& e ) {
if ( std::string const *stack boost::get_error_info<stack_error_info>(e) ) {
std::cout << stack << std::endl;
}
}
关于c++ - 从未处理的异常的C++堆栈跟踪?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3355683/