为什么在我的析构函数中抛出时 std::terminate 没有被调用
why is std::terminate not called when throwing in my destructor
当使用以下代码从析构函数中抛出时,我试图“看到”对 std::terminate() 的调用:
#include <stdexcept>
struct boom {
~boom() {
throw std::logic_error("something went wrong");
}
};
int main() {
boom();
}
用 g++ 和 运行 代码编译:
# ./a.out
terminate called after throwing an instance of 'std::logic_error'
what(): something went wrong
Aborted (core dumped)
到目前为止一切顺利,似乎按预期工作(调用 terminate())。但是当试图在 gdb 中终止终止时,该函数没有被命中并且回溯只显示中止:
(gdb) b std::terminate
Breakpoint 2 at 0x7f60a3772240 (2 locations)
(gdb) r
Starting program: a.out
terminate called after throwing an instance of 'std::logic_error'
what(): something went wrong
Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007f2c241eb921 in __GI_abort () at abort.c:79
#2 0x00007f2c24628957 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3 0x00007f2c2462eae6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4 0x00007f2c2462db49 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5 0x00007f2c2462e4b8 in __gxx_personality_v0 () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6 0x00007f2c23c05573 in ?? () from /lib/x86_64-linux-gnu/libgcc_s.so.1
#7 0x00007f2c23c05ad1 in _Unwind_RaiseException () from /lib/x86_64-linux-gnu/libgcc_s.so.1
#8 0x00007f2c2462ed47 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#9 0x0000558cee09593a in boom::~boom() ()
#10 0x0000558cee0958dd in main ()
(gdb)
这种行为让我感到困惑,是不是我遗漏了什么?
编辑:
使用 clang++ 进行的相同测试,并且命中了 std::terminate 断点:
Breakpoint 1, 0x0000000000400750 in std::terminate()@plt ()
(gdb) bt
#0 0x0000000000400750 in std::terminate()@plt ()
#1 0x00000000004009bf in __clang_call_terminate ()
#2 0x000000000187eef0 in ?? ()
#3 0x00000000004009a4 in boom::~boom() ()
#4 0x00000000004008f1 in main ()
(gdb)
您 运行 符合假设规则。
C++ 编译器 允许 基本上按照他们认为合适的方式重写您的整个程序,只要副作用保持不变。
副作用的定义非常明确,“调用某个函数”不是其中的一部分。因此,如果编译器可以确定这是 std::terminate()
对程序产生的唯一副作用,则完全允许编译器直接调用 abort()
。
获取更多详细信息
当使用以下代码从析构函数中抛出时,我试图“看到”对 std::terminate() 的调用:
#include <stdexcept>
struct boom {
~boom() {
throw std::logic_error("something went wrong");
}
};
int main() {
boom();
}
用 g++ 和 运行 代码编译:
# ./a.out
terminate called after throwing an instance of 'std::logic_error'
what(): something went wrong
Aborted (core dumped)
到目前为止一切顺利,似乎按预期工作(调用 terminate())。但是当试图在 gdb 中终止终止时,该函数没有被命中并且回溯只显示中止:
(gdb) b std::terminate
Breakpoint 2 at 0x7f60a3772240 (2 locations)
(gdb) r
Starting program: a.out
terminate called after throwing an instance of 'std::logic_error'
what(): something went wrong
Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007f2c241eb921 in __GI_abort () at abort.c:79
#2 0x00007f2c24628957 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3 0x00007f2c2462eae6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4 0x00007f2c2462db49 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5 0x00007f2c2462e4b8 in __gxx_personality_v0 () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6 0x00007f2c23c05573 in ?? () from /lib/x86_64-linux-gnu/libgcc_s.so.1
#7 0x00007f2c23c05ad1 in _Unwind_RaiseException () from /lib/x86_64-linux-gnu/libgcc_s.so.1
#8 0x00007f2c2462ed47 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#9 0x0000558cee09593a in boom::~boom() ()
#10 0x0000558cee0958dd in main ()
(gdb)
这种行为让我感到困惑,是不是我遗漏了什么?
编辑:
使用 clang++ 进行的相同测试,并且命中了 std::terminate 断点:
Breakpoint 1, 0x0000000000400750 in std::terminate()@plt ()
(gdb) bt
#0 0x0000000000400750 in std::terminate()@plt ()
#1 0x00000000004009bf in __clang_call_terminate ()
#2 0x000000000187eef0 in ?? ()
#3 0x00000000004009a4 in boom::~boom() ()
#4 0x00000000004008f1 in main ()
(gdb)
您 运行 符合假设规则。
C++ 编译器 允许 基本上按照他们认为合适的方式重写您的整个程序,只要副作用保持不变。
副作用的定义非常明确,“调用某个函数”不是其中的一部分。因此,如果编译器可以确定这是 std::terminate()
对程序产生的唯一副作用,则完全允许编译器直接调用 abort()
。