当前位置: 首页 > 知识库问答 >
问题:

为什么'std::exit'没有按预期触发析构函数?

薛博赡
2023-03-14
#include <cstdlib>
#include <thread>
#include <chrono>
#include <iostream>

using namespace std;
using namespace std::literals;

struct A
{
    int n_ = 0;
    A(int n) : n_(n) { cout << "A:" << n_ << endl; }
    ~A() { cout << "~A:" << n_ << endl; }
};

A a1(1);

int main()
{
    std::thread([]()
    {
        static A a2(2);
        thread_local A a3(3);
        std::this_thread::sleep_for(24h);
    }).detach();

    static A a4(4);
    thread_local A a5(5);

    std::this_thread::sleep_for(1s);
    std::exit(0);
}

我的编译器是clang 5.0-std=c++1z

输出如下:

A:1
A:2
A:4
A:5
A:3
~A:5
~A:2
~A:4
~A:1

具有线程本地存储持续时间的对象的析构函数...保证被调用。

共有1个答案

韩峰
2023-03-14

只有调用exit的线程才能保证销毁具有线程存储持续时间的对象。引用C++14(N4140),[Support.Start.Term]18.5/8(强调我的):

[[noreturn]] void exit(int status)

函数exit()在此国际标准中具有其他行为:

  • 首先,销毁具有线程存储持续时间且与当前线程关联的对象。接下来,销毁具有静态存储持续时间的对象,并调用通过调用atexit注册的函数。有关析构和调用的顺序,请参见3.6.3。(自动对象不会因为调用exit()而被销毁。)如果由于exit未为引发的异常提供处理程序,因此控制保留了由exit调用的注册函数,则应调用std::terminate()(15.5.1).
  • 接下来,所有打开的带有未写缓冲数据的C流(由 中声明的函数签名中介)将被刷新,所有打开的C流将被关闭,所有通过调用tmpfile()创建的文件将被删除。
  • 最后,控制返回到宿主环境。如果状态为零或exit_success,则返回状态成功终止的实现定义形式。如果status为exit_failure,则返回status unsuccess终止的实现定义形式。否则返回的状态是实现定义的。

因此,标准不能保证销毁线程存储持续时间与调用exit的线程以外的其他线程相关联的对象。

 类似资料:
  • 我正在学习Java,正在使用java 8,spring 5.3.9和Apache Tomcat 9。我已经将我的jar文件添加到我的构建路径中的类路径中,将Apache Tomcat添加到我的服务器中,我的项目运行得非常好。现在我开始使用beans和xml文件,我遇到了一个问题。我的代码的一部分被触发,另一部分被忽略。 我有以下界面 FortuneService.java: 和一个快乐财富服务类:

  • 考虑以下代码: 旁白:请不要评论“这段代码很糟糕”,“你不能在全局对象中使用析构函数”(你可能不应该这样做),也不要在评论中探究XY问题。这是一个好奇的学生提出的学术问题,他知道如何更好地解决原来的问题,但却在探索C++的广阔天地时偶然发现了这个怪癖。

  • 这是我想要得到的输出: 代码如下:https://jsfiddle.net/t5ewp8ax/ 似乎台词: 被正确解析为

  • 在JavaScript中,我按住两个键,并且被完美触发。当我释放其中一个键时,被触发。到目前为止一切都很好。但是我仍然按住一个键,那么为什么没有被触发呢?我需要在我的游戏中发生这种情况。我做错了什么吗?这是预期的反应吗?有什么解决办法吗?

  • 这是我到目前为止用于此任务的代码: 但是如果我输入了一个无效的日期,比如,它将转换为,而不是抛出异常。