【问题标题】:Prevent gcc/libstdc++ from calling terminate on throwing from throw() method防止 gcc/libstdc++ 在从 throw() 方法抛出时调用终止
【发布时间】:2012-10-26 11:51:22
【问题描述】:

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

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

但内部发生异常确实,gcc 将终止应用程序(带有消息“在抛出 'xyz' 实例后调用终止”)。

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

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

【问题讨论】:

  • 只有 catch() 里面的例子会有所帮助...
  • 那么你想让一个函数不能抛出异常,但能够抛出异常?
  • 我不控制双方(既不扔()也不扔)。不是我的代码。但我必须处理这种组合。
  • 如果是 throw() 那么你需要捕获并处理方法内部发生的所有异常。
  • 我更愿意找到一个比修改 1000 个现有源文件更简单的解决方案。假设我只是想找到解决方案,只是为了好玩。

标签: c++ linux exception gcc


【解决方案1】:

你试过GCC manual吗?

-fno-enforce-eh-specs

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

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

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

编辑:即使使用-fno-enforce-eh-specs,它仍会调用std::terminate()

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不能被省略。当抛出异常时,它将被捕获。

【讨论】:

  • 似乎不起作用。这段代码死了: void method() throw(){throw "";} int main(){try{method();}catch(...){}}
  • 如果违反异常规范,您的建议有效;例如如果是 throw(std::exception)。不幸的是,在 throw() 的情况下它仍然会死掉。
  • 显然您并没有真正阅读我的答案。 正如文档所说,“编译器仍会根据规范进行优化”,例如当对 method() 的调用可以内联到捕获站点时,它没有帮助,
  • 不是内联的,我用 objdump -d 验证过。
  • 我说可以内联不是内联,这只是一个例子,当它没有帮助时,我不会列出所有可能的情况或不起作用。在您的情况下,编译器可以看到对函数的调用,并且函数声明说它不会抛出,因此编译器优化了 catch
【解决方案2】:

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

您可以使用std::set_unexpected 提供自己的意外异常处理程序:默认调用std::terminate,但您可以做一些不同的事情(例如记录和吞下异常)。但是,您是否可以有效地恢复取决于您的程序。另外,我已经看到它被标记为已弃用,因此依赖它可能不是最好的主意。

【讨论】:

  • 不,不可能吞下 set_unexpected 处理程序中的异常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多