如何在C++中获取自定义异常抛出调用者的详细信息?
获取C++异常抛出的调用者信息
你现在遇到的问题是自定义异常无法追踪到具体抛出的函数,对吧?我来给你几个实用的方案:
方案1:在异常类中存储完整调用栈信息
你可以修改自定义的myexception类,让它在构造时就捕获当前的调用栈信息,这样在what()方法里就能返回包含调用链路的详细内容了。示例代码如下:
#include <exception> #include <string> #include <execinfo.h> // GCC环境下用于获取调用栈 #include <cstring> #include <iostream> class myexception : public std::exception { private: std::string err_msg; void capture_stacktrace() { void* callstack[128]; int frames = backtrace(callstack, 128); char** strs = backtrace_symbols(callstack, frames); if (strs) { for (int i = 0; i < frames; ++i) { err_msg += strs[i]; err_msg += "\n"; } free(strs); } err_msg += "My exception happened"; } public: myexception() { capture_stacktrace(); } virtual const char* what() const noexcept override { return err_msg.c_str(); } }; void testException(){ throw myexception(); // 注意:这里要抛出临时对象,而非全局对象,避免多次抛出共享实例 } void doSomething2(){ testException(); } void doSomething1(){ doSomething2(); } int main () { try { doSomething1(); } catch (std::exception& e) { std::cout << e.what() << '\n'; } return 0; }
注意:backtrace和backtrace_symbols是GCC的扩展API,Windows环境下需要替换为CaptureStackBackTrace这类系统API。另外你之前抛出全局对象myex的写法不推荐,多次抛出会共享同一个实例,容易导致信息混乱。
方案2:仅传递抛出异常的函数名
如果不需要完整调用栈,只想知道是哪个函数抛出的异常,可以在异常类里添加成员变量存储函数名,抛出时通过标准宏传入:
#include <exception> #include <string> #include <iostream> class myexception : public std::exception { private: std::string err_msg; public: myexception(const std::string& func_name) { err_msg = "My exception happened in function: " + func_name; } virtual const char* what() const noexcept override { return err_msg.c_str(); } }; void testException(){ throw myexception(__func__); // 使用C++11标准宏__func__获取当前函数名 } void doSomething2(){ testException(); } void doSomething1(){ doSomething2(); } int main () { try { doSomething1(); } catch (std::exception& e) { std::cout << e.what() << '\n'; } return 0; }
__func__是C++11纳入标准的宏,会返回当前函数的名称字符串,兼容性非常好。
方案3:调试阶段用工具直接追踪
如果你只是在调试时需要定位异常来源,完全可以借助编译器和调试工具的内置支持:
- 编译代码时加上
-g参数生成调试信息:g++ -g your_code.cpp -o your_program - 启动GDB调试:
gdb ./your_program - 设置异常断点:
catch throw - 运行程序:
run
当异常抛出时,GDB会自动暂停,输入bt命令就能看到完整的调用栈,直观又高效。
内容的提问来源于stack exchange,提问作者scoder
相关产品推荐
相关产品推荐

