如何使c++像python一样给出详细的异常信息

How to make C++ give detailed exception information just like python does?

本文关键字:信息 异常 一样 c++ 何使 python      更新时间:2023-10-16

使用python,当发生异常时,即使没有捕获,我也可以获得有关哪个文件引发错误的详细信息:

def hello():
    raise Exception;
hello() 
Execution result >>
Traceback (most recent call last):
  File "exceptionExample.py", line 4, in <module>
    hello()
  File "exceptionExample.py", line 2, in hello
    raise Exception;
Exception

对于c++,这些信息不是那么有用:

#include <iostream>
using namespace std;
class Error
{
};
int value()
{
    throw Error();
}
int main(int argc, char *argv[]) {
    value();
}
>>
terminate called after throwing an instance of 'Error'
Run Command: line 1: 52772 Abort trap: 6           ./"$2" "${@:3}"

我如何使c++给出更详细的信息,关于哪个模块引发了错误,从哪一行?

您可以在异常消息中使用__FILE____LINE__定义。

例如:

#include <stdexcept>
class Error : public std::runtime_error
{
  public:
    Error (const std::string &message)
      : std::runtime_error(message)
    {}
};
int value()
{
    std::stringstream ss;
    ss << "Issues at " << __FILE__ << " on line " << __LINE__;
    throw Error(ss.str());
}

在这个例子中,我使Error继承自std::runtime_error(它有一个构造函数,允许您将消息作为字符串传递)…

另外,看看这个SO问题:全局异常处理——注意关于使用set_terminate函数的答案。这将允许您安装一个全局处理程序,以确保按需要打印消息。下面是关于set_terminate()的一些信息。

Python为未捕获的异常提供堆栈跟踪。我提供的答案只告诉您文件和行号。如果您需要堆栈跟踪,一些评论者参考了其他一些SO问题,这些问题给出了如何在c++中做到这一点的建议。但是,要注意这个问题的非标准解决方案。

您可以创建异常,以便在创建异常时包装堆栈跟踪。但是,请注意只在调试模式下记录此日志,因为日志堆栈跟踪可能是一个安全问题。

还可以使用调试器。

没有可移植的方法来获取堆栈跟踪,一个技巧是在函数上下文中使用对象来保存信息

struct StackTraceInfo {
    const char *filename;
    int line;
    static std::vector<StackTraceInfo *> stack;
    StackTraceInfo(const char *filename, int line) :
      filename(filename), line(line)
    {
        stack.push_back(this);
    }
    ~StackTraceInfo()
    {
        stack.pop_back();
    } 
};
#define ENTER StackTraceInfo(__FILE__, __LINE__) sinfo_;

在每个函数中只在body的最开始添加一行ENTER

int foo() {
    ENTER
    ....
    return 42;
}
在抛出异常的情况下,您需要使用全局StackTraceInfo::stack向量的内容保存当前堆栈跟踪,以便显示消息的人可以访问该信息。请注意,您无法访问异常处理程序中的堆栈信息,因为此时堆栈已经展开。

还要注意,如果你的应用程序是多线程的,你需要为每个线程使用单独的堆栈,使用局部存储而不是全局存储。

使用标准c++ 11可以获得与Python回溯非常相似的东西,使用:

std::nested_exceptionstd::throw_with_nested

在这里和这里的StackOverflow中描述了如何在不需要调试器或繁琐的日志记录的情况下对代码中的异常进行反跟踪,只需编写一个适当的异常处理程序即可重新抛出嵌套异常。

注意,你必须包装所有的函数,你想出现在你的try/catch的回溯,你需要非标准宏(__FILE__, __func__, __LINE__)自动添加源位置信息。

由于您可以对任何派生异常类执行此操作,因此您可以向此类回溯中添加大量信息!你也可以看看我在GitHub上的MWE或我的"trace"库,其中的反向跟踪看起来像这样:

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"