零成本异常处理与setjmp/longjmp

16 c++ gcc exception-handling g++ exception

假设设置恢复点存在相关成本,可以像这样优化循环:

while (doContinue) {
   try {
     doSomeWork ();
   }
   catch (...) {}
}
Run Code Online (Sandbox Code Playgroud)

进入这样的事情:

while (doContinue) {
   try {
      do {
        doSomeWork ();
      } while (doContinue);
      break;
   } catch (...) {}
}
Run Code Online (Sandbox Code Playgroud)

但是,如果平台支持零成本异常处理,那么这种优化没有任何意义.

有人能指出我是如何在不同的体系结构上实现零成本异常处理的,并且有一种方法可以确定编译器/代码生成器可用的底层机制,以便在编译时决定是否优化这样做.例如,编译器可以为您优化它,如果它可以假设doSomeWork ()没有与循环相关的副作用吗?

小智 12

只有在使用目标时才能使用零成本方法.如果可用,它将被大多数生产质量的C++编译器使用.否则编译器将使用setjmp/longjmp方法.

执行速度setjmp/longjmp较慢.

但是,即使使用了setjmp/longjmp方法,使用异常机制也可以比检查每个函数的返回代码产生更高的性能,例如在问题中使用双循环优化.

找出目标是否支持零成本方法以及编译器是否正在使用的唯一方法是将C++代码转换为汇编并进行分析.另一种解决办法是调用gnat--RTS=zcx和检查错误,如果gnat是可用的.但这并不能保证它将被C++编译器使用.

因此,一般来说,如果程序大小不是问题并且零成本异常可用,则使用异常来处理意外情况要比检查每个函数的返回代码要好得多.否则,在某些情况下,可以使用异常来优化代码.

使用,但不要滥用!

PS:我最后写了一篇关于此的文章.


Cha*_*tin 7

我认为你过高估计"零成本"在这里意味着什么.这是关于它的LLVM文档 ; 它的主要作用似乎是异常和上下文处理代码是在编译时构建的,因此在执行正常进行时,运行时没有额外的成本,成为时空权衡.在您的示例中,我相信会产生两倍的"着陆点",增加大小并减慢异常处理速度.

  • 我的意思是在运行时零成本.不仅LLVM,而且GCC,我相信所有其他人,在编译时为支持它的平台生成处理.因此在输入`try`块时没有设置恢复点.如果是这种情况,我的优化将消除在循环中的每次迭代中设置该恢复点.然而,在零成本的情况下,它在循环之外添加了两个或三个指令.这不会减慢运行时间.但困扰我的是如何弄清楚C++编译器将使用什么,setjmp/longjmp或在编译时生成处理代码. (3认同)