为什么抛出异常这么慢
why throw an exception is so slow
int foo(int n)
{
//if (n==0) throw 0; // throw is so slow
if (n==0) return 0; //return is faster
//foo(n-1); sorry , it should be ..
return foo(n-1);
}
int main()
{
for (int i=0;i<50000;++i)
{
try{
foo(80);
}
catch(...){
}
}
return 0;
}
当我使用返回 0 时,for 循环执行得非常快,而使用 throw 0,执行速度非常慢。我知道异常处理效率不高,但我很惊讶它太慢了。
不要使用 throw 作为返回
你的代码也有缺陷,我假设你想返回一些东西n!=0
抛出异常是一种复杂的机制,可能是编译器后端中最难处理的部分。它涉及倒带堆栈,调用范围内对象的析构函数,可能处理大多数平台上的安全检查并找到可以处理异常的上行框架。
在您的情况下,它可能更快一些,但远不如呼叫返回快。
将 gcc 的优化版本与 return 0
进行比较:
foo(int): # @foo(int)
xorl %eax, %eax
ret
main: # @main
xorl %eax, %eax
ret
并且版本例外(两种情况下都打开了 -O3 优化(:
foo(int): # @foo(int)
pushq %rbp
movq %rsp, %rbp
movl $4, %edi
callq __cxa_allocate_exception
movl $0, (%rax)
movq %rax, %rdi
movl typeinfo for int, %esi
xorl %edx, %edx
callq __cxa_throw
main: # @main
pushq %rbp
movq %rsp, %rbp
pushq %rbx
pushq %rax
movl $-1, %ebx
.LBB1_1: # =>This Inner Loop Header: Depth=1
incl %ebx
cmpl $49999, %ebx # imm = 0xC34F
jg .LBB1_4
movl $4, %edi
callq __cxa_allocate_exception
movl $0, (%rax)
movq %rax, %rdi
movl typeinfo for int, %esi
xorl %edx, %edx
callq __cxa_throw
movq %rax, %rdi
callq __cxa_begin_catch
callq __cxa_end_catch
jmp .LBB1_1
.LBB1_4:
xorl %eax, %eax
addq $8, %rsp
popq %rbx
popq %rbp
ret
GCC_except_table1:
.byte 255 # @LPStart Encoding = omit
.byte 3 # @TType Encoding = udata4
.byte 175 # @TType base offset
.zero 1,128
.zero 1
.byte 3 # Call site Encoding = udata4
.byte 39 # Call site table length
.long .Lset0
.long .Lset1
.long 0 # has no landing pad
.byte 0 # On action: cleanup
.long .Lset2
.long .Lset3
.long .Lset4
.byte 1 # On action: 1
.long .Lset5
.long .Lset6
.long 0 # has no landing pad
.byte 0 # On action: cleanup
.byte 1 # >> Action Record 1 <<
.byte 0 # No further actions
.long 0 # TypeInfo 1
正如你所看到的,代码更加复杂:设置和分配着陆垫,个性例程完成它们的工作,等等。而且这些东西也很难优化。您为使用的内容付费。
以下是 gcc 编译您的代码的内容,并带有foo
return 0;
(有或没有修复以确保foo
总是返回一些东西,尽管它在技术上是 UB 没有修复(:
main:
xorl %eax, %eax
ret
编译器可以证明循环不会产生可观察到的副作用,并抛弃整个事情。
相关文章:
- 如果不包含 pthread,为什么 GCC 的线程标准库实现会抛出异常?
- ZMQ::send() 抛出异常并终止 QNX 进程.为什么以及如何从中恢复?
- 为什么g_object_set抛出异常(vcruntime140.dll)?
- 为什么访问模板化变体作为返回值抛出异常
- 为什么重新抛出异常会丢弃"what()"给出的信息?
- 为什么在这个动态数组中抛出异常
- ATL/COM:为什么 CComSafeArray::GetCount() 会为空数组抛出异常
- 为什么这个正则表达式抛出异常
- 为什么当我在使用空 throw() 说明符指定的函数中抛出异常时没有调用 std::unexpected()
- 为什么VS2013在销毁唯一指针时会抛出异常
- 为什么WP8.1运行时组件在调用boost::filesystem::file_size()时抛出C++异常
- 为什么抛出异常这么慢
- 为什么我不能从我的抛出异常中打印出错误?
- 为什么不能从析构函数抛出异常,但可以从复制构造函数抛出异常
- 为什么 SIGSEGV 的信号处理程序没有捕获我的C++抛出异常?
- 为什么 lock() 在死锁的情况下不抛出异常
- 为什么_ftscanf_s会抛出异常而_ftscanf不会
- 为什么在抛出异常时析构函数调用两次
- 为什么在抛出异常指针时要通过引用使用 catch
- 为什么 std::string::substr 会抛出异常而不是返回空字符串