c – 为什么不throw()和noexcept有什么开销?
在C 03中将throw()作为异常说明符添加,但在C11中对于noexcept说明符已被弃用.
在分析一些代码后,使用throw(),noexcept和简单的函数找到速度,我发现所有这些函数与函数调用大致相同. 结果: throw() noexcept plain old function 11233 ms 11105 ms 11216 ms 11195 ms 11122 ms 11150 ms 11192 ms 11151 ms 11231 ms 11214 ms 11218 ms 11228 ms compiled with MinGW using g++ -o test.exe inc.cpp no.cpp -std=c++11 -O3 以下是我用于配置文件的代码: int main() { unsigned long long iter = (unsigned long long)1 << (unsigned long long)40; auto t1 = std::chrono::high_resolution_clock::now(); for(unsigned long long i = 0; i < iter; i++) { #ifdef THROW throw_func(); #elif defined NOEXCEPT noexcept_func(); #else std_func(); #endif } auto t2 = std::chrono::high_resolution_clock::now(); std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count() << " ms" << std::endl; } 功能定义如下: unsigned long long val = 1; struct exception { }; void throw_func(void) throw() { if (!val++) throw exception(); } void noexcept_func(void) noexcept { if (!val++) throw exception(); } void std_func(void) { if (!val++) throw exception(); } 我对这些结果感到惊讶,因为我的印象是throw()和noexcept为函数添加了一些开销. 与常规函数调用相比,为什么throw()和noexcept会增加函数调用的任何开销? 解决方法
gcc和clang具有非常相似的代码生成,因为它们在很大程度上与ABI兼容.我只是cl to回答你的问题,但我的答案应该适用于你的gcc编译器.
可以使用-S命令行标志来反汇编throw_func,noexcept_func和std_func.在这样做时,您将注意到,这三个功能都会产生非常相似的装配. 差异包括: >这个函数的名称不一样:__Z10throw_funcv,__Z13noexcept_funcv和__Z8std_funcv. 总之,这三个功能的唯一区别是在“异常路径”中.而“特殊的路径”增加了代码大小,但是永远不会被你的主机执行.在现实世界的代码中,增加的代码大小可能会影响运行时性能.然而,对于经常执行并且足够小以适应高速缓存(例如此测试)的代码,代码大小命中不会导致任何运行时性能命中. 为了完整,这里是noexcept_func程序集. LBB0_1以下的一切都是处理异常路径的. LBB0_1:通过Ltmp1:抛出异常. Ltmp2:是一个“着陆垫”,运行时将分支到一个异常尝试通过这里解开.而GCC_except_table0是异常表本身. .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 "242200200" ## @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 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |