在 catch 块之前抛出异常后如何打印堆栈跟踪(堆栈展开)

How to print stacktrace once an exception is thrown before the catch block (stack unwinding)

提问人:Mazen Ak 提问时间:11/4/2021 最后编辑:Mazen Ak 更新时间:11/17/2021 访问量:417

问:

假设我们有以下代码:

#include <exception>


void funcA() {
    funcB();
}

void funcB() {
    funcC();
}

void funcC() {
    funcD();
}

void funcD() {
    throw std::runtime_error("Exception!!"); //3
}

void funcE() {
    int * p;
    delete p; //4
}

int main (int argc, char **argv) {
    
    try {
        funcA(); //1
    } catch (std::exception exc) {
        std::cerr << exc.what() << endl; //2
        return EXIT_FAILURE;
    }
    
    return EXIT_SUCCESS;
}

我想以多线程有效的方式打印带有引发的异常的行号的堆栈跟踪。

在过去的几天里,我一直在检查人们正在做的解决方案和方法,但不幸的是,在我的情况下没有任何用处。例如,我可以使用boost库或任何其他库,但这里的问题是我必须捕获异常才能执行此操作,如果您的代码有数百个嵌套函数,则此方法效率不高。你不能只是把它们都一遍,然后把每一个都包起来,然后分别处理它们。boost::stacktrace::stacktrace()//2try-catch

所以基本上我需要做的是,如果抛出异常,我应该能够在'//2中打印异常的堆栈跟踪//3

我知道堆栈展开及其工作原理,但据我所知,每当您的代码到达 catch 块时,这意味着异常堆栈已被展开并且您无法获取它。如果我错了,请纠正我!

有没有办法在解开异常堆栈之前至少添加类似于中间件的东西?还是我必须手动完成?

编辑:

此外,当我可以时会发生什么是内存访问异常,但从未捕获此异常。有没有办法捕获此类异常,或者至少在崩溃之前打印其堆栈跟踪?funcE()

注意:

我在 Linux 和 macOS、带有硅 Web 框架的 C++11 上运行我的代码。 这是一个大系统,所以我正在尝试实现一些可以在整个系统中使用的日志记录机制。

C++11 异常 跟踪 堆栈展开

评论

0赞 Some programmer dude 11/4/2021
与其抛出一个通用异常,比如 ,不如添加你自己的类层次结构,其中包含语义上更重要的异常,这有助于缩小可能引发每个异常的可能位置。然后为每个异常添加一些重要的描述,以便每个文本都是唯一的,并且可用于定位引发异常的确切位置。runtime_error
0赞 Some programmer dude 11/4/2021
另一种可能的方法(可以与上述方法结合使用)是使用一个特殊函数,甚至可能是一个预处理器宏来抛出异常,这个函数或宏可以将此类信息(如回溯或源位置)添加到日志中或作为异常本身的一部分。
0赞 Mazen Ak 11/4/2021
我添加了 作为示例,代码可能会抛出任何类型的异常,即使我有一个自定义异常类@Someprogrammerdude我也无法为系统中的所有函数添加块runtime_errortry-catch
0赞 Mazen Ak 11/4/2021
关于宏的事情,我可以搜索任何示例或概念吗?@Someprogrammerdude 提前致谢,伙计:)
0赞 Some programmer dude 11/4/2021
你不应该到处添加,只在它有意义的某些点上添加,并且实际上可以处理异常。另请注意,某些异常可能无法处理,您应该让它们继续终止程序。还要记住,例外情况应该保留给真正的特殊问题。如果您有可以从中恢复的错误(例如无法打开可选文件),则通常无需为此引发异常。try catch

答:

0赞 Mazen Ak 11/17/2021 #1

我发布这个是为了防止有人遇到同样的问题并想要一个快速有用的答案。

我最终使用这个要点覆盖了主要的 C++ 抛出异常行为

我更改了函数中的一些内容以解决我自己的问题,并用于获得更易于人类阅读的堆栈跟踪。__cxa_throwboost::stacktrace