C++: "try { foo(); } catch (...) { throw; }" 可以优化为 "foo();" 吗?

6
在C++中,以下代码为:
try {
  foo();
} catch (...) {
  throw;
}

与像这样只调用foo在语义上相同吗?
foo();

如果是这样的话,我能否期望一款最先进的编译器将第一个版本转换为第二个版本(在启用优化时进行编译)?
换句话说,如果我使用 NDEBUG 和启用了优化来编译此代码。
try {
  foo();
} catch (...) {
  assert(some_check());
  throw;
}

我可以为您进行翻译。该句的意思是:我可以假定这个版本不会比这个丑陋版本更慢吗?
#ifndef NDEBUG
  try {
#endif
    foo();
#ifndef NDEBUG
  } catch (...) {
    assert(some_check());
    throw;
  }
#endif

2
不在实践中。 - Veedrac
我只是猜测,但如果foo()内部没有抛出异常,可以安全地假设编译器可以进行此优化。 - DeiDei
2
如果 foo 不能抛出异常(编译器知道这一点,例如通过 noexcept),编译器将删除任何相关的异常处理分支。但问题比那更普遍。 - Veedrac
1
即使 try { throw 0; } catch (...) {}try { throw 0; } catch (...) { throw; } 看起来生成的代码不太优化,但异常并不容易优化。 - Veedrac
1个回答

3
不,这两者并不等价。
当没有异常处理程序时,堆栈展开是实现定义的([except.handle]p9)。当存在处理程序但仅重新抛出异常时,堆栈必须至少展开到重新抛出异常的点。
也就是说:
struct S { ~S(); };
void foo() { S s; throw 0; }
int main() {
  try { foo(); }
  catch(...) { throw; }
}

这必须调用s的析构函数。当移除try { ... } catch (...) { throw; }时,不再需要调用s的析构函数。
甚至根据s的析构函数执行的内容,可能永远不会到达重新抛出异常的地方,例如添加以下内容:
#include <stdlib.h>
S::~S() { exit(0); }

现在,程序必须成功运行,但是当try { ... } catch (...) { throw; }被移除时,这不再是必需的,而且在真实系统中可能会发生崩溃。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接