来自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.
当编译器优化时,它会删除所有类型的检查,它会打破函数之间的界限,甚至可能会避免开发人员在某些情况下放入代码中的系统调用。所以:
答案 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(); } }
,也会占用更多的空间。