在我最近编写的一个程序中,我想记录我的“业务逻辑”代码何时在第三方或项目 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 块中,在另一种情况下删除了“抛出”并放置了“返回”。
我现在看到我的解决方案很脆弱;它不是面向未来的修改证明。
我想要一个没有这些问题的更好的解决方案。
我有另一个没有上述问题的潜在解决方案,但我想知道其他人对此有何看法。它使用 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
. - 还有另一种方法来完成我想要的吗?
注意:我已经更新了这个问题。具体来说,我有:
- 在函数调用周围添加了最初缺少的
try
/ 。catch
log
- 添加了跟踪
std::uncaught_exception
施工状态。这可以防止在另一个析构函数的“try”块内创建此对象的情况,该析构函数是作为异常堆栈展开的一部分触发的。 - 修复了新的 'potential_function' 以创建命名对象,而不是像以前一样的临时对象。