考虑以下代码片段:
void f();
void a() { f(); }
void b() noexcept { f(); }
在上面的场景中,f
的主体对于当前翻译单元中的编译器是不可见的。因此,由于 b
被标记为 noexcept
,必须在调用方生成额外的代码以确保异常被捕获并且 std::terminate
被调用。
这就是 clang++ -Ofast -std=c++2a
所做的(主干版本):
a(): # @a()
jmp f() # TAILCALL
b(): # @b()
push rax
call f()
pop rax
ret
mov rdi, rax
call __clang_call_terminate
__clang_call_terminate: # @__clang_call_terminate
push rax
call __cxa_begin_catch
call std::terminate()
但是,g++ -Ofast -std=c++2a
不会(trunk 版本):
a():
jmp f()
b():
jmp f()
g++
是如何解决这个问题的?由于 f
的主体不可见,难道不应该在调用方生成代码吗?
...或者这只是一个奇怪的 Compiler Explorer 怪癖?
最佳答案
正如@ach 回答的那样,有一个 bug opened on gcc bug tracker .但如果我可以这么说,这不是一个主要问题。
影响是异常会泄漏而不是终止程序但是:
- 如果你想在未捕获的异常上调用终止,那已经是这样了
- 如果您想要不抛出异常的安全保证,那么它不会提供。
我能想到的唯一情况是在开发过程中。或者在环境中,如果契约(Contract)被破坏(当生命受到威胁时)必须失败;在这种情况下,编译器和要使用的功能受到严格控制。
Andrzej 在 his article - noexcept — what for ? 中表现出色
关于c++ - 在可见性有限的 `std::terminate` 函数中调用 `noexcept` - gcc vs clang codegen,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50047658/