gcc and clang have very similar code generation as they are largely ABI compatible with one another. I only have clang to answer your question with, but my answer should apply to your gcc compiler fairly closely.
One can disassemble throw_func
, noexcept_func
and std_func
using the -S
command line flag. Upon doing so, you will note that the three functions all generate remarkably similar assembly.
Differences include:
The mangled name of the functions will differ: __Z10throw_funcv
, __Z13noexcept_funcv
, and __Z8std_funcv
.
The "normal path" assembly code will be identical for all three functions except perhaps for the names of labels.
throw_func
and noexcept_func
will generate "exception tables" after the code. These tables instruct the low-level C++ runtime library how to unwind the stack. This includes instructions on what destructors must be run, what catch blocks to try, and in the case of these two functions, what to do if an exception tries to propagate out. throw_func
will contain a call to ___cxa_call_unexpected
and noexcept_func
will contain a call to ___clang_call_terminate
(for gcc that will be named something else).
std_func
will not contain calls to unexpected
nor terminate
. Nor will it have an "exception table". There are no destructors to run, no try/catch clauses to land in, and there is no need to call unexpected
or terminate
.
In summary, the only difference in these three functions is in the "exceptional path". And the "exceptional path" adds code size, but is never executed by your main
. In real-world code, just the added code size can impact run-time performance. However for code that is executed often, and small enough to fit in cache (such as this test), the code size hit won't cause any run-time performance hit.
For completeness, here is the noexcept_func
assembly. Everything below LBB0_1:
is to handle the exceptional path. LBB0_1:
thru Ltmp1:
throws the exception. Ltmp2:
is a "landing pad" that the runtime will branch to if an exception tries to unwind through here. And GCC_except_table0:
is the exception table itself.
.globl __Z13noexcept_funcv
.align 4, 0x90
__Z13noexcept_funcv: ## @_Z13noexcept_funcv
.cfi_startproc
.cfi_personality 155, ___gxx_personality_v0
Leh_func_begin0:
.cfi_lsda 16, Lexception0
## BB#0:
pushq %rbp
Ltmp3:
.cfi_def_cfa_offset 16
Ltmp4:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp5:
.cfi_def_cfa_register %rbp
movq _val(%rip), %rax
leaq 1(%rax), %rcx
movq %rcx, _val(%rip)
testq %rax, %rax
je LBB0_1
LBB0_2:
popq %rbp
retq
LBB0_1:
movl $1, %edi
callq ___cxa_allocate_exception
Ltmp0:
movq __ZTI9exception@GOTPCREL(%rip), %rsi
xorl %edx, %edx
movq %rax, %rdi
callq ___cxa_throw
Ltmp1:
jmp LBB0_2
LBB0_3:
Ltmp2:
movq %rax, %rdi
callq ___clang_call_terminate
.cfi_endproc
Leh_func_end0:
.section __TEXT,__gcc_except_tab
.align 2
GCC_except_table0:
Lexception0:
.byte 255 ## @LPStart Encoding = omit
.byte 155 ## @TType Encoding = indirect pcrel sdata4
.asciz "\242\200\200" ## @TType base offset
.byte 3 ## Call site Encoding = udata4
.byte 26 ## Call site table length
Lset0 = Leh_func_begin0-Leh_func_begin0 ## >> Call Site 1 <<
.long Lset0
Lset1 = Ltmp0-Leh_func_begin0 ## Call between Leh_func_begin0 and Ltmp0
.long Lset1
.long 0 ## has no landing pad
.byte 0 ## On action: cleanup
Lset2 = Ltmp0-Leh_func_begin0 ## >> Call Site 2 <<
.long Lset2
Lset3 = Ltmp1-Ltmp0 ## Call between Ltmp0 and Ltmp1
.long Lset3
Lset4 = Ltmp2-Leh_func_begin0 ## jumps to Ltmp2
.long Lset4
.byte 1 ## On action: 1
.byte 1 ## >> Action Record 1 <<
## Catch TypeInfo 1
.byte 0 ## No further actions
## >> Catch TypeInfos <<
.long 0 ## TypeInfo 1
.align 2