【问题标题】:why is std::terminate not called when throwing in my destructor为什么在我的析构函数中没有调用 std::terminate
【发布时间】:2021-05-27 12:18:30
【问题描述】:

当使用以下代码从析构函数抛出时,我试图“查看”对 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)

到目前为止一切顺利,似乎按预期工作(调用终止())。但是当尝试在 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)

【问题讨论】:

  • 没有终止处理程序,调用终止和直接调用中止没有区别。
  • 我同意从程序的角度来看最终没有真正的区别,但文档不应该说“std::terminate is called”,而应该说“可能被称为“...
  • @OznOg "std::terminate is called" 是一个比你想象的更宽松的陈述,因为 as-if 规则:en.cppreference.com/w/cpp/language/as_if
  • @frank 你可能是对的,是时候发布答案了;)

标签: c++ c++11 terminate


【解决方案1】:

你遇到了 as-if 规则。

C++ 编译器允许在它们认为合适的情况下重写您的整个程序,只要副作用保持不变。

副作用的定义非常明确,“调用某个函数”不是其中的一部分。因此,如果编译器可以确定这是 std::terminate() 对程序产生的唯一副作用,则完全允许编译器直接调用 abort()

您可以在https://en.cppreference.com/w/cpp/language/as_if获取更多详细信息

【讨论】:

  • 是的,此外,即使 std::terminate 被调用,也没有什么可以承受的,它不会被内联到某个地方。谢谢你的提醒。
  • @OznOg 好吧,内联只是 as-if 规则下允许的众多转换之一。没有迂腐的“此外”。
  • 当然,我说只是为了强调一个非常简单的(内联)会给出问题,甚至不会侵犯“std::terminate”将被调用。
猜你喜欢
  • 2018-10-20
  • 1970-01-01
  • 1970-01-01
  • 2016-04-12
  • 2017-03-22
  • 2020-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多