65.9K
CodeProject 正在变化。 阅读更多。
Home

捕获和记录异常

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (3投票s)

2010年8月13日

CPOL

4分钟阅读

viewsIcon

34118

downloadIcon

346

一种在 C++ 中捕获异常并记录它们的简单方法。

引言

C++ 开发人员通常试图通过在他们的代码中放置日志语句(cout 等)来查找错误/异常,以查找发生了什么。 有些人选择使用 Dr.Watson 等软件来获取调用堆栈并费力找到异常位置。 众所周知,捕获异常的唯一方法是使用 try/catch 块。 但放置这些块会降低代码的可读性,并且可能更容易出错,因为 catch 块中的语句。

我在这里介绍一些易于使用的宏,它们将这些 try/catch 块放入代码中。 这些宏将允许您捕获异常并将异常位置记录到文件中。 如果您在代码中使用这些宏,则每当发生异常时,您都将能够看到调用堆栈。

也可以禁用异常抛出,以便您的程序可以无需异常而运行。

Using the Code

使用宏非常简单。 假设您有一个名为 myMethod 的函数

void myMethod()
{
    EXLOG_START
    ...
    ...
    EXLOG_END
}

EXLOG_START 是一个简单的 try 表达式。 另一方面,EXLOG_END 是带有错误日志记录机制的 catch 块。

myMethod 函数中发生异常时,它将被捕获并记录在一个文件中。 之后,如果没有禁用异常抛出(将被告知),则异常将被抛给 myMethod 的调用者函数。 如果您在函数中放置了 EXLOG 语句,则异常将被记录到 main 函数。

您可以禁用 EXLOG 的异常抛出,以便捕获异常、记录异常,并且程序将尝试继续运行。 您可以在代码的任何部分使用以下方法设置它

EXLOG::setIsThrowExceptions(false); //default: true

一些函数可能会返回值而不是 void。 对于这些函数,您应该使用另一个宏 EXLOG_END_WITH_RETURN,以允许这些函数在发生异常时返回值

int myMethodWithReturn() 
{ 
    EXLOG_START
    ...
    ...
    EXLOG_END_WITH_RETURN(-1) 
}

因此,如果存在异常,myMethodWithReturn 将返回 -1(假设这是此函数的默认值),并且调用者将获得 -1,并且程序将继续运行。

除了这些宏之外,ExLogger 类也很重要。 它是将信息记录到文件的类。 它使用 boost 的日期时间类为文件/日志获取唯一名称。 因此,您应该将 boost 的库添加到您的项目中。

您还可以使用 ExLogger 将任何内容记录到文件中。 它是一个单例类,它重载了 << 运算符,这使您可以像写入 cout 一样编写简单易读的代码。 您可以使用宏 EXLOG 获取一个实例

EXLOG << myInt << "sth" << myValue << EXLOG_ENDL("");

EXLOG_ENDL 类似于 std::endl,它会导致日志流被刷新到文件中。

关注点

在代码中,EXLOG 宏可以用定义更改:EXLOG_ENABLED。 我已将此定义放入标头中,但您可以将其放入您的预处理器部分,以便您可以使用一个定义启用/禁用 EXLOG 相关代码。

如果未启用 EXLOG_ENABLED,则宏将被替换为 // 注释表达式。 因此,表达式将被注释掉。 这种用法只有一个小问题:如果想用这个定义禁用 EXLOG 语句,应该把 EXLOG 语句放在一行。

所以,例如

EXLOG << myInt << "sth" << myValue << EXLOG_ENDL(""); 

是安全的。 但

EXLOG << myInt << 
               "sth" << myValue 
<< EXLOG_ENDL("");  

如果您未定义 EXLOG_ENABLED,将导致编译错误。

但我认为这种方法比使用

#ifdef _DEBUG
    Exlogger::instance() << myInt << "sth" << myValue << EXLOG_ENDL("");
#endif

注释

  • 使用默认的项目设置,硬件相关的异常,例如除以零、悬空指针使用等,无法使用标准的 try/catch 块捕获。 您应该通过以下路径更改您的项目设置以启用此功能
  • Project Properties >> C/C++ >> Code Generation >> Enable C++ Exceptions 

    并将该值设置为“是,带 SEH 异常(/EHa)”。

  • 另一个设置是关于 STL 类。 这些类包含许多断言。 众所周知,断言无法捕获。 为了避免这种情况,您还应该在项目的预处理器设置中定义这些值
  • _SECURE_SCL=0 ve _HAS_ITERATOR_DEBUGGING=0

    但请记住在所有导入的项目中设置这些预处理器设置! 因此,最后一个设置是可选的。 如果您没有定义这些预处理器值,则 STL 异常可能不会被捕获/记录,但会通过断言通知您。

讨论

您可能认为放置 try/catch 可能会影响性能。 但是在使用 try/catch 块时,您可以放心。 我搜索了很多论坛,也进行了性能测试。 使用 try/catch 块和不使用它们之间只有微不足道的差异。

进行安全开发。 :)

© . All rights reserved.