g ++ -fno-enforce-eh-specs - 为什么/如何违反C ++标准?

时间:2016-12-25 22:09:28

标签: c++ gcc exception-handling compiler-optimization compiler-flags

来自man gcc

  -fno-enforce-eh-specs
      Don't generate code to check for violation of exception specifications
      at run time.  This option violates the C++ standard, but may be useful
      for reducing code size in production builds.

当编译器优化时,它会删除所有类型的检查,它会打破函数之间的界限,甚至可能会避免开发人员在某些情况下放入代码中的系统调用。所以:

  • 为什么异常规范违规检查如此特殊以至于无法跳过?
  • 究竟在检查什么?
  • 如果使用此开关对减少代码大小非常有用,那么为什么C ++标准需要这些检查呢?我认为这个想法是尽可能零开销的抽象。

2 个答案:

答案 0 :(得分:4)

(现在是旧的?)标准要求声明为strlen(str)的函数不能抛出void f() throw(x);以外的任何异常(或者可能从x派生出来?)。如果它试图抛出其他内容,则应调用x,并可能最终调用std::unexpected()来终止该程序。

但是如果在编译时无法确定异常的确切类型,则可能需要运行时检查以确定异常是否属于可接受的类型。

当然,如果通过此选项删除了该检查,则错误的异常可能从函数中逃脱。这将违反标准。

答案 1 :(得分:2)

  

为什么异常规范违规检查如此特殊以至于无法跳过?   究竟在检查什么?

这已经得到了解答,但为了完整性,我的答案也是:对于具有throw(...)noexcept规范的函数,当异常被抛出时,std::unexpected()或{必须调用{1}}。

实际上,他们会变成像

这样的东西
std::terminate()

非常类似于:

void f();
void g() noexcept { f(); }
  

如果使用此开关对减小代码大小非常有用,那么为什么C ++标准需要这些检查呢?我认为这个想法是可能的零开销抽象。

事实上。但没有办法在没有开销的情况下实现这一点。编译器已经设法以这样的方式实现异常:只要没有抛出异常,在运行时执行的代码与没有异常处理的版本相同。从这个意义上讲,在具有合适ABI的平台上,已经实现了零开销异常。但是,它们仍然使用特殊标记来注释该代码,这些标记允许运行时库找出在异常最终抛出时要调用的代码。那些特殊的标记占据了空间。最终解释这些标记的代码也占用空间。而实际的异常处理代码,即使它只是void f(); void g() { try { f(); } catch (...) { std::terminate(); } } ,也会占用更多的空间。