可移植地处理C ++中的异常错误

时间:2020-03-05 18:46:21  来源:igfitidea点击:

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

现有代码在少数地方使用了__try {...} __except(1){...}`块,因此几乎没有什么(缺少内存不足类型错误?)会使程序退出而没有做些什么记录。

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

编辑:感谢Visual Studio中指向/ EH选项的指针,我现在需要的是一些有关如何在Linux上处理信号的示例。我发现了这则来自2002年的消息。

除了" SIGFPE"和" SIGSEVG"之外,我还需要注意其他什么信号? (最关心那些可能因我做错事而引起的问题)

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

我会得到什么信号,之后通常无法记录错误消息? (内存不足,还有什么?)

我该如何以可移植的方式处理异常和(最重要的)信号,以确保代码至少在Linux和MingW上可以正常工作。 #ifdef可以。

我不仅拥有记录故障的包装过程的原因是,出于性能方面的考虑,我将一些数据保存到磁盘上直到最后一分钟,因此,如果出现问题,我想尝试所有可能的方法,然后再将数据写出退出。

解决方案

回答

为什么不使用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等受管系统不同,只要有实际上不会引发任何异常)。

回答

尝试{xxx} catch(...){xxx}更具可移植性,但捕获的可能性不大。这取决于编译器设置和环境。

使用默认的VC ++设置,异步(SEH)错误不会传递到C ++ EH基础结构中。要捕获它们,我们需要使用SEH处理程序(__try / __ except)。 VC ++允许我们通过C ++错误处理来路由SEH错误,这可以使catch(...)捕获SEH错误。这包括内存错误,例如空指针取消引用。细节。

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

回答

对于可移植性,要尝试的一件事是对大多数常见异常使用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 ++相对未知的部分,即使在部分(小规模)堆栈损坏的情况下,在某些情况下也可以提供恢复。

最后,是的,我们可能希望研究可以自己连续处理的信号或者可能中止的信号,并且如果希望使用较少的处理机制,则可以考虑调用new运算符的非抛出版本,并在需要时进行编译以不生成浮点异常(我们可以始终在FP结果上检查isnan(。),isfinite(。)来保护自己)。

关于最后一点,请小心:我注意到浮点结果分类函数可以在linux和Windows下的不同标头中...因此我们可能必须对这些包含进行条件化。

如果我们感到不高兴,请使用setjmp和longjmp编写所有内容(这是个玩笑...)。

回答

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

这是我为另一个问题也适用于问题的示例:链接

另外,我们可以捕获多个:

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 */
}

回答

catch(...)捕获C ++异常已经使我们陷入暮光之城。

试图捕获未被catch(...)捕获的错误,将使我们直接进入未定义的行为。没有C ++代码可以保证正常工作。最小记录代码可能会导致导弹发射。

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

如果我们根本原因之外有错误处理代码故障,则事后调试会变得很丑陋。