Reputation: 523
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;
}
I tested above program. when I use return 0, the for-loop executed very fast, while use throw 0, very very slow. I know that exception-handle is not efficient, but I am surprized that it is so slow.
Upvotes: 0
Views: 220
Reputation: 43662
Don't use throw as a return
Your code is also flawed, I'm assuming you wanted to return something for n!=0
Throwing exceptions is a complex mechanism and probably the hardest part to deal with in a compiler's back-end. It involves rewinding the stack, calling destructors of the objects in scope, probably dealing with security checks on most platforms and finding an upframe which can handle the exception.
In your case it might be somewhat faster but not nearly as fast as a call return.
Compare the optimized version for gcc with return 0
:
foo(int): # @foo(int)
xorl %eax, %eax
ret
main: # @main
xorl %eax, %eax
ret
and with the exception version ( -O3 optimizations on in both cases ):
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
As you can see the code is way more involved: landing pads are set and allocated, personality routines do their job, etc.. take a look at here. And this stuff is also hard to optimize. You pay for what you use.
Upvotes: 2
Reputation: 137425
Here's what gcc compiles your code to, with a return 0;
in foo
(with or without a fix to ensure that foo
always returns something, though it's technically UB without a fix):
main:
xorl %eax, %eax
ret
The compiler can prove that the loop produces no observable side effects, and throw out the whole thing.
Upvotes: 2