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;
}
我测试了以上程序。当我使用return 0时,for循环执行得非常快,而使用throw 0,非常非常慢。我知道异常句柄效率不高,但我觉得它太慢了。
答案 0 :(得分:2)
不要使用throw作为回报
您的代码也有缺陷,我假设您想要返回n!=0
抛出异常是一种复杂的机制,可能是编译器后端最难处理的部分。它涉及倒带堆栈,调用范围内对象的析构函数,可能在大多数平台上处理安全检查并找到可以处理异常的upframe。
在你的情况下,它可能会稍微快一点但不如呼叫返回快。
将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
正如您所看到的,代码涉及的方式更多:着陆垫已设置和分配,个性例程可以完成其工作等等。请查看here。这个东西也很难optimize。 您支付使用的费用。
答案 1 :(得分:2)
以下是gcc编译代码的内容,return 0;
中的foo
(有或没有修复,以确保foo
始终返回某些内容,尽管它有&#39} ;技术上UB没有修复):
main:
xorl %eax, %eax
ret
编译器可以证明循环不会产生可观察到的副作用,并抛弃整个事物。