防止gcc / libstdc ++在throw()方法的throw上调用terminate

时间:2012-10-26 11:51:23

标签: c++ linux exception gcc

如果我有一个标记为throw()的方法,例如

 void method() throw()
 {
      // do some stuff, call other functions
 }

然而异常发生在里面发生,gcc将终止应用程序(消息“在抛出'xyz'实例后调用终止”)。

有没有办法避免这种行为?

例如,命令行开关忽略throw()内容或强制生成eh_frame。等

2 个答案:

答案 0 :(得分:2)

您是否尝试过GCC manual

  

-fno-enforce-eh-specs

     

不要生成代码以在运行时检查是否违反了异常规范。此选项违反了C ++标准,但可能对减少生产版本中的代码大小很有用,就像定义“NDEBUG”一样。这不会为用户代码授予违反异常规范而抛出异常的权限;编译器仍然会根据规范进行优化,因此抛出意外异常会导致运行时出现未定义的行为。

强制生成EH帧,但它应该停止对std::unexpected()的调用,因此可能对您的情况有用。

正如文档所说,“编译器仍然根据规范进行优化”,例如当对method()的调用可以内联到catch站点时,它没有帮助,因为编译器假定不需要catch,因为空的异常规范说没有异常将被抛出,因此如果异常是抛出它不会被抓住。如果对method()的调用无法进入catch网站,它似乎可以正常工作,异常会在不调用method()的情况下离开std::unexpected(),并且可以在堆栈中被捕获。

修改:即使使用std::terminate(),这仍然会调用-fno-enforce-eh-specs

void func() throw() { throw ""; }
void func2() { func(); }
int main() { try { func2(); } catch (...) { } }

编译器可以看到对func2的调用只调用了无抛出函数,因此永远不需要catch,因此优化掉了。抛出异常时,它不会被捕获。

-fno-enforce-eh-specs一起使用,但不会终止:

/* func2.cc */
void func() throw();
void func2() { func(); }

/* main.cc */
void func2();
int main() { try { func2(); } catch (...) { } }

这里,在编译main.cc时,编译器无法判断func2是否要抛出,因为它没有异常规范,其定义在main.cc中不可见,所以catch不能省略。抛出异常时会被捕获。

答案 1 :(得分:1)

您可以通过调用std::set_terminate来提供自己的终止处理程序...但是我不认为从那里返回是合法的,所以它唯一能做的就是以某种方式终止。

您可以使用std::set_unexpected提供自己的意外异常处理程序:默认情况下调用std::terminate,但您可以执行不同的操作(例如记录和吞咽异常)。您是否可以有效恢复取决于您的计划。此外,我已经看到它被标记为已弃用,所以依靠这可能不是最好的主意。