gpt4 book ai didi

c++ - 触发异常时应该如何记录?

转载 作者:可可西里 更新时间:2023-11-01 18:39:40 25 4
gpt4 key购买 nike

在我最近编写的一个程序中,当我的“业务逻辑”代码在第三方或项目 API 中触发异常时,我想记录下来。 (澄清一下,我想在使用 API 导致异常时记录日志。这可能比实际的 throw 高很多帧,也可能比实际的 catch 低很多帧>(可以记录异常负载的位置。))我做了以下操作:

void former_function()
{
/* some code here */
try
{
/* some specific code that I know may throw, and want to log about */
}
catch( ... )
{
log( "an exception occurred when doing something with some other data" );
throw;
}
/* some code here */
}

简而言之,如果发生异常,创建一个 catch-all 子句,记录错误,然后重新抛出。在我看来,这是安全的。我知道一般来说,包罗万象被认为是不好的,因为根本没有对异常的引用来获取任何有用的信息。但是,我只是要重新抛出它,所以不会丢失任何东西。

现在,它自己没问题,但其他一些程序员修改了这个程序,最终违反了上述规定。具体来说,他们在一种情况下将大量代码放入 try block 中,而在另一种情况下删除了“throw”并放置了“return”。

现在我发现我的解决方案很脆弱;它不是 future 修改的证明。

我想要一个没有这些问题的更好的解决方案。

我有另一个没有上述问题的潜在解决方案,但我想知道其他人对此有何看法。它使用 RAII,特别是一个“Scoped Exit”对象,如果 std::uncaught_exception 在构建时不为真,但在时隐式触发销毁:

#include <ciso646> // not, and
#include <exception> // uncaught_exception

class ExceptionTriggeredLog
{
private:
std::string const m_log_message;
bool const m_was_uncaught_exception;
public:
ExceptionTriggeredLog( std::string const& r_log_message )
: m_log_message( r_log_message ),
m_was_uncaught_exception( std::uncaught_exception() )
{
}
~ExceptionTriggeredLog()
{
if( not m_was_uncaught_exception
and std::uncaught_exception() )
{
try
{
log( m_log_message );
}
catch( ... )
{
// no exceptions can leave an destructor.
// especially when std::uncaught_exception is true.
}
}
}
};

void potential_function()
{
/* some code here */
{
ExceptionTriggeredLog exception_triggered_log( "an exception occurred when doing something with some other data" );
/* some specific code that I know may throw, and want to log about */
}
/* some code here */
}

我想知道:

  • 从技术上讲,这会很有效吗?最初它似乎有效,但我知道使用 std::uncaught_exception 有一些注意事项。
  • 还有其他方法可以实现我想要的吗?

注意:我已经更新了这个问题。具体来说,我已经:

  • log 函数调用周围添加了最初缺失的 try/catch
  • 添加了跟踪构造时的 std::uncaught_exception 状态。这可以防止在另一个析构函数的“try” block 内创建此对象的情况,该析构函数作为异常堆栈展开的一部分被触发。
  • 修复了新的“potential_function”以创建一个命名对象,而不是像以前那样的临时对象。

最佳答案

我对你的方法没有意见,但看起来很有趣!我有另一种方法也可以满足您的需求,并且可能更通用一些。不过,它需要来自 C++11 的 lambda,这在您的情况下可能是也可能不是问题。

这是一个简单的函数模板,它接受 lambda、运行它并捕获、记录并重新抛出所有异常:

template <typename F>
void try_and_log (char const * log_message, F code_block)
{
try {
code_block ();
} catch (...) {
log (log_message);
throw;
}
}

你使用它的方式(在最简单的情况下)是这样的:

try_and_log ("An exception was thrown here...", [&] {
this_is_the_code ();
you_want_executed ();
and_its_exceptions_logged ();
});

正如我之前所说,我不知道它与您自己的解决方案相比如何。请注意,lambda 正在捕获其封闭范围内的一切,这非常方便。另请注意,我还没有实际尝试过,因此可能会导致编译错误、逻辑问题和/或核 war 。

我在这里看到的问题是,将其包装到宏中并不容易,并希望您的同事正确编写 [=] {} 部分而且所有的时间可能太多了!

出于包装和防白痴的目的,您可能需要两个宏:一个 TRY_AND_LOG_BEGIN 发出第一行直到 lambda 的左大括号和一个 TRY_AND_LOG_END发出右大括号和括号。像这样:

#define TRY_AND_LOG_BEGIN(message)  try_and_log (message, [&] {
#define TRY_AND_LOG_END() })

然后你像这样使用它们:

TRY_AND_LOG_BEGIN ("Exception happened!")  // No semicolons here!
whatever_code_you_want ();
TRY_AND_LOG_END ();

这是 - 取决于您的观点 - 是净 yield 还是净损失! (我个人更喜欢直接的函数调用和 lambda 语法,这给了我更多的控制权和透明度。

另外,也可以在代码块的末尾写入日志信息;只需切换 try_and_log 函数的两个参数即可。

关于c++ - 触发异常时应该如何记录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15504166/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com