简体   繁体   English

C ++异常抛出/捕获优化

[英]C++ Exception Throw/Catch Optimizations

It seems to me that if you have some C++ code like this: 在我看来,如果你有一些像这样的C ++代码:

int f()
{
  try {
    if( do_it() != success ) {
      throw do_it_failure();
    }
  } catch( const std::exception &e ) {
    show_error( e.what() );
  }
}

The C++ compiler should be able to optimize the throw and catch into almost a simple goto. C ++编译器应该能够优化throw并捕获几乎简单的goto。

However, it seems to me from my experience viewing disassembly and stepping through code that the compilers always jump through the very messy exception handling libraries. 但是,从我查看反汇编和单步执行代码的经验来看,编译器总是跳过非常混乱的异常处理库。

Why do they do that? 他们为什么这样做? Is there some language requirement that prevents optimizing? 是否存在一些阻止优化的语言要求? What if it was: 如果它是:

int f()
{
  try { throw std::runtime_error("Boo!"); }
  catch ( const std::exception &e ) { std::cout << e.what() << std::endl; }
}

Why does the compiler not just rewrite that as 为什么编译器不只是重写为

int f()
{
  std::cout << "Boo!" << std::endl;
}

Because do_it() could throw a different exception, before you throw do_it_failure(); 因为在抛出do_it_failure();之前, do_it()可能抛出不同的异常do_it_failure();

As for your second example, a compiler could do it, but it would have to be treated as a special case, so why bother for such a pathological case? 至于你的第二个例子,编译器可以做到这一点,但它必须被视为一个特例,那么为什么还要为这种病态案例而烦恼呢?

Why do they do that? 他们为什么这样做?

Because C++ exception are for, well, exceptional circumstances and performance under exceptional circumstances doesn't really matter. 因为C ++例外适用于, 特殊情况下的特殊情况和性能并不重要。

C++' exceptions were designed with that in mind, making sure compiler vendors could deliver near-optimal performance in the common case of no exceptions being thrown, at the cost of worse-than-possible performance in the odd case when exceptions are thrown. 考虑到这一点,设计了C ++的异常,确保编译器供应商可以在没有异常抛出的常见情况下提供接近最优的性能,但是在抛出异常的奇怪情况下,代价可能性能更差。

From the very beginning users were encouraged to use exceptions only under exceptional circumstances, and implementers were encouraged to optimize the no-exception case (destructor addresses must be stored somewhere in order to call destructors when an exception comes by) at the cost of the exceptional case. 从一开始就鼓励用户仅在特殊情况下使用异常,并且鼓励实现者优化无异常情况(析构函数地址必须存储在某处以便在异常发生时调用析构函数),代价是异常案件。
And while implementers could certainly spend resources at also optimizing the odd exceptional case, most users wouldn't like that, since there's always so much more important things that need improvment. 虽然实施者当然可以花费资源来优化奇怪的例外情况,但大多数用户都不喜欢这样,因为总是有更重要的东西需要改进。

I think the accepted answer is quite uninformative if not wrong, so even after so many years I feel the need to offer a proper answer. 我认为,如果没有错误,接受的答案是非常缺乏信息的,所以即使经过这么多年,我觉得有必要提供正确的答案。

Speculating on why the compiler implementors chose to not put effort on any particular feature is just, well... speculation. 推测为什么编译器实现者选择不对任何特定功能付出努力只是......好猜测。 The fact that exceptions are thrown only in exceptional circumstances is not generally felt as a reason to not optimize the performance of such code. 仅在特殊情况下抛出异常的事实通常不被认为是不优化此类代码性能的理由。 On the contrary, even though it is true that throwing code is not optimized at the expense of non-throwing code, the exception throwing and handling infrastructure is nevertheless optimized very carefully. 相反,尽管抛出代码并没有非抛出代码为代价进行优化,但抛出和处理异常的例外情况仍然非常谨慎地进行了优化。

Furthermore, that piece of code might feel so contrived that is not worth considering, but this is not true: it may result from inlining and optimizing of much more complex code, and optimizing it could result into simpler code that allows other optimization passes to fire, or the containing function to be further inlined. 此外,这段代码可能感觉如此做作,不值得考虑,但事实并非如此:它可能来自内联和优化更复杂的代码,并且优化它可能导致更简单的代码,允许其他优化传递触发,或包含进一步内联的函数。 Optimization passes like these, when correct and efficient to implement, are always worth of at least being considered, no matter how contrived the original piece of code might look. 无论原始代码看起来多么做作,这些优化传递都是正确的,有效的实现,总是值得至少考虑。 Otherwise, even fundamental passes like dead code elimination would be avoided because "dead code should not be written in the first place". 否则,即使是死代码消除的基本过程也会被避免,因为“死代码不应该首先写入”。 Which is obviously not the case. 这显然不是这样的。

Hence I just do not agree with the accepted answer. 因此,我只是不同意接受的答案。 The fact that exceptions should be thrown exceptionally is not the reason why this code is not optimized. 应该异常抛出异常的事实并不是未对此代码进行优化的原因。

The reason is purely technical, and is explained in this email from the clang development mailing list: http://lists.llvm.org/pipermail/cfe-dev/2015-March/042035.html 原因纯粹是技术性的,并在clang开发邮件列表的电子邮件中进行了解释: http//lists.llvm.org/pipermail/cfe-dev/2015-March/042035.html

To summarize, the language allows code called inside the catch block to rethrow the exception in any point "without ever having seen" the exception object: 总而言之,该语言允许在catch块内调用的代码在“没有看到”异常对象的任何点重新抛出异常:

void g() { throw; }

Hence, consider the OP code: 因此,考虑OP代码:

int f()
{
  try { throw std::runtime_error("Boo!"); }
  catch ( const std::exception &e ) { std::cout << e.what() << std::endl; }
}

For what the compiler is concerned, e.what() , or the two invocations of operator<< , may rethrow the exception, hence optimizing away the exception handling code would break the semantics of the program. 对于编译器而言, e.what()operator<<的两次调用可能会重新抛出异常,因此优化掉异常处理代码会破坏程序的语义。

Ensuring this is not the case would require "whole-program knowledge", as written in the above email message. 确保不是这种情况需要“整个程序知识”,如上面的电子邮件中所述。 Even simpler cases could be optimized, such as: 即使是简单的情况下, 可以优化,如:

int func() {
  try {
    throw 42;
  }catch(int x) {
    return x;
  }
}

The above code can be transformed into return 42 . 上面的代码可以转换为return 42 There are no technical reasons that impede it. 没有技术原因阻碍它。

Still, most common compilers do not do it ( godbolt ). 尽管如此,大多数常见的编译器都没有这样做( godbolt )。 This time, we can tell from an actual source, the email linked above, that Clang developers (we cannot say anything for other compilers) do not think this optimization to be worth, probably because it would only apply to catch blocks that do not do function calls. 这一次,我们可以从实际来源,上面链接的电子邮件,Clang开发人员(我们不能为其他编译器说什么)不认为这个优化是值得的, 可能是因为它只适用于不执行的catch块函数调用。

Anyway, the message says nothing about whether they would accept a patch to do so. 无论如何,该消息没有说明他们是否会接受这样做的补丁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM