在C ++中用于异常堆栈

今天,在我的C ++多平台代码中,我尝试了解每个函数。 在每个catch块中,我将当前函数的名称添加到异常并再次抛出,以便在最上面的catch块(我最终打印异常的详细信息的地方)中有完整的调用堆栈,这有助于我追踪异常的原因。

这是一个很好的做法,还是有更好的方法来获取异常的调用堆栈?


不,它是非常可怕的,我不明白为什么你需要在异常本身中调用堆栈 - 我发现异常的原因,行号和代码的文件名,这些代码在发生初始异常时足够了。

话虽如此,如果您确实需要一个堆栈跟踪,那么要在异常抛出站点上生成调用堆栈信息ONCE。 没有一种可移植的方式可以做到这一点,但使用像http://stacktrace.sourceforge.net/与VC ++类似的库并不太难。


你在做什么不是好的做法。 原因如下:

这是没有必要的。
如果您在调试模式下编译项目,以便生成调试信息,则可以轻松地在调试器(例如GDB)中获取异常处理的回溯。

2.这很麻烦。
这是你必须记住要添加到每个功能。 如果你碰巧错过了一个函数,那可能会引起很大的困惑,特别是如果那是导致异常的函数。 任何看着你的代码的人都必须意识到你在做什么。 另外,我敢打赌,你使用了类似__FUNC__或__FUNCTION__或__PRETTY_FUNCTION__的东西,这很遗憾地说都是非标准的(在C ++中没有标准方法来获取函数的名称)。

3.速度很慢。
C ++中的异常传播已经非常慢了,添加这个逻辑只会使代码路径变慢。 如果您使用宏来捕获和重新抛出,那么这不是问题,您可以轻松地避开捕获并重新引发代码的发布版本。 否则,性能可能会成为问题。

良好的做法
尽管在每个函数中捕获和重新构建堆栈跟踪可能不是一个好习惯,但最好附上最初抛出异常的文件名,行号和函数名。 如果你使用boost :: exception和BOOST_THROW_EXCEPTION,你将会免费得到这个行为。 将解释性信息附加到您的异常也很好,这将有助于调试和处理异常。 也就是说,所有这些都应该在构建例外时发生; 一旦建立起来,就应该允许它传播给它的处理程序......你不应该反复地捕捉和重新抛出超过严格的必要条件。 如果你需要捕捉并重新抛出特定的函数来附加一些重要的信息,那没问题,但捕获每个函数中的所有异常以及附加已有信息的目的太多了。


一个可能更优雅的解决方案是构建一个Tracer宏/类。 因此,在每个函数的顶部,你写下如下所示的内容:

TRACE()

和宏看起来像这样:

Tracer t(__FUNCTION__);

并且类Tracer将该函数名称添加到构造中的全局堆栈上,并在销毁时自行删除。 然后,该堆栈始终可用于记录或调试,维护要简单得多(一行),并且不会产生异常开销。

实现的示例包括诸如http://www.drdobbs.com/184405270,http://www.codeproject.com/KB/cpp/cmtrace.aspx和http://www.codeguru.com/cpp/vs /debug/tracing/article.php/c4429。 另外Linux的功能就像这样http://www.linuxjournal.com/article/6391可以更加本地化,​​就像这个堆栈溢出问题所描述的那样:当我的gcc C ++应用程序崩溃时如何生成堆栈跟踪。 ACE的ACE_Stack_Trace也值得一看。

无论如何,异常处理方法是粗糙的,不灵活的,并且在计算上是昂贵的。 如果需要,类构建/宏解决方案要快得多,并且可以编译为发布版本。

链接地址: http://www.djcxy.com/p/86051.html

上一篇: stack for exceptions in C++

下一篇: How do I find the name of the calling function?