4

With python, when an exception occurs, I get detailed information about what file raised an error, even without a catch:

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

With C++, the information is not that useful:

#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}"

How can I make C++ give more detailed information about what module raised an error and from which line?

I'd like to use it without a catch clause.

4

4 回答 4

3

您可以在异常消息中使用__FILE__and__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 问题: Global Exception Handling - 请注意有关使用该set_terminate函数的答案。这将允许您安装一个全局处理程序,以确保根据需要打印消息。这是有关set_terminate()的一些信息。

Python 为未捕获的异常提供堆栈跟踪。我提供的答案只告诉你文件和行号。如果您需要堆栈跟踪,一些评论者参考了其他一些 SO 问题,这些问题提供了有关如何在 C++ 中执行此操作的建议。但是,请注意此问题的非标准解决方案。

于 2013-06-14T15:21:08.430 回答
0

您可以创建异常,以便它们在创建时包装堆栈跟踪。仍然请注意仅在调试模式下记录它,因为记录堆栈跟踪可能是一个安全问题。

也使用调试器可以帮助你。

于 2013-06-14T15:21:49.843 回答
0

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

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_;

在每个函数中只需ENTER在正文的开头添加一行

int foo() {
    ENTER
    ....
    return 42;
}

如果在抛出之前发生异常,您需要使用全局StackTraceInfo::stack向量的内容保存当前堆栈跟踪,以便显示消息的人可以访问此信息。请注意,您无法访问异常处理程序中的堆栈信息,因为此时堆栈已经展开。

另请注意,如果您的应用程序是多线程的,您需要使用线程本地存储而不是全局存储为每个线程使用单独的堆栈。

于 2013-06-14T15:41:08.327 回答
0

幸运的是,使用标准 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"
于 2019-12-24T16:32:18.117 回答