可以在C ++中处理异常错误

时间:2008-09-02 10:57:11

标签: exception visual-c++ gcc cross-platform portability

我正在努力将Visual C ++应用程序移植到GCC(应该建立在MingW和Linux上)。

现有的代码在一些地方使用__try { ... } __except(1) { ... }块,所以几乎没有(可能没有内存类型错误?)会使程序退出而不做一些最小的日志记录。

与GCC做类似的事情有哪些选择?

编辑:感谢Visual Studio中指向/ EH选项的指针,我现在需要的是如何在Linux上处理信号的一些示例。我从2002年开始发现this message

我应该注意除SIGFPESIGSEVG以外还有哪些其他信号? (主要关心可能从做错事的那些人)

赏金信息: 我希望我的应用程序能够在退出之前自动记录尽可能多的错误条件。

我可以获得哪些信号以及通常无法在之后记录错误消息? (内存不足,还有什么?)

如何以可移植的方式处理异常和(最重要的)信号,使得代码至少在Linux和MingW上运行相同。 #ifdef没问题。

我不仅仅有一个记录失败的包装器进程的原因是出于性能原因我将一些数据保存到磁盘直到最后一分钟,所以如果出现问题我想尽一切可能尝试写入退出前的数据。

5 个答案:

答案 0 :(得分:10)

尝试{xxx} catch(...){xxx}会更便携,但可能无法捕获。这取决于编译器设置和环境。

使用默认的VC ++设置,异步(SEH)错误不会传递到C ++ EH基础结构;为了捕获它们,你需要使用SEH处理程序(__try / __除外)。 VC ++允许您通过C ++错误处理来路由SEH错误,这允许catch(...)捕获SEH错误;这包括内存错误,如空指针解引用。 Details

但是,在Linux上,Windows使用SEH的许多错误都是通过信号指示的。这些都没有被try / catch捕获;要处理它们,你需要一个信号处理程序。

答案 1 :(得分:0)

为什么不使用C ++标准异常而不是MSFT的专有扩展? C ++有一个异常处理概念。

struct my_exception_type : public logic_error {
    my_exception_type(char const* msg) : logic_error(msg) { }
};

try {
    throw my_exception_type("An error occurred");
} catch (my_exception_type& ex) {
    cerr << ex.what << endl;
}

C ++也有一个“catchall”子句,因此如果要记录异常,可以使用以下包装器:

try {
    // …
}
catch (...) {
}

然而,这在C ++中效率不高,因为创建这样的通用包装意味着处理代码必须由编译器插入每个后续堆栈帧中(与.NET中的托管系统不同)只要没有实际抛出异常,异常处理就不会产生额外费用。

答案 2 :(得分:0)

为了便于移植,要尝试的一件事是对大多数vanilla异常使用try-catch块,然后设置一个终止处理程序(set_terminate_handler)以使最小的钩子可用于灾难性的退出条件。您还可以尝试添加类似atexit或on_exit处理程序的内容。当然,当你输入这些功能时,你的执行环境可能是奇怪的或腐败的,所以要小心你认为一个理智的环境。

最后,当使用常规的try-catch对时,你可以考虑使用函数try块而不是在函数体中打开try块:

int foo(int x) try {
  // body of foo
} catch (...) {
   // be careful what's done here!
}

它们是一个相对未知的C ++块,在某些情况下甚至可以在部分(小规模)堆栈损坏的情况下提供恢复。

最后,是的,您可能想要调查哪些信号可以自行处理或可以中止哪些信号,如果您想要更少的处理机制,您可以考虑调用非投掷版本如果需要,编译器不会生成浮点异常(您可以随时检查isnan(。),isfinite(。),在FP结果上保护自己)。

关于最后一点,请注意:我注意到浮点结果分类函数可以在linux和windows下的不同标题中......所以你可能必须对那些包含条件化。

如果你感到顽皮,可以使用setjmp和longjmp(这是一个笑话......)来写出来。

答案 3 :(得分:0)

使用catch(...)捕获C ++异常已使您进入黄昏区域。

尝试捕获catch(...)未捕获的错误会使您完全置于未定义的行为中。没有C ++代码可以保证工作。您的最小日志记录代码可能会导致导弹发射。

我的建议是不要尝试catch(...)。只捕获可以有意义且安全地记录的异常,并让操作系统处理其余的事务(如果有的话)。

如果您在根本原因之上有错误处理代码失败,那么事后调试会变得很难看。

答案 4 :(得分:-1)

易于使用,便携且几乎不使用任何资源的一种方法是捕获空类。我知道这听起来可能很奇怪,但它可能非常有用。

以下是我针对您的问题提出的另一个问题的示例:link

此外,您可以拥有超过1个捕获:

try
{
   /* code that may throw exceptions */
}
catch (Error1 e1)
{
   /* code if Error1 is thrown */
}
catch (Error2 e2)
{
   /* code if Error2 is thrown */
}
catch (...)
{
   /* any exception that was not expected will be caught here */
}