C++ 为什么'std::exit'没有像预期的那样触发析构函数?

C++ 为什么'std::exit'没有像预期的那样触发析构函数?,c++,c++11,global-variables,destructor,thread-local-storage,C++,C++11,Global Variables,Destructor,Thread Local Storage,请注意,没有~A:3,这意味着对象a3没有被破坏 然而,根据: std::exit导致正常程序终止。下面介绍了几个清理步骤 执行: 具有线程本地存储持续时间的对象的析构函数。。。是 保证会被叫来 这里的问题是,当您退出进程时,线程将(在大多数现代多任务操作系统上)被强制终止。线程的终止发生在操作系统级别,操作系统对对象或析构函数一无所知。具有线程存储持续时间的对象保证仅对调用退出的线程进行销毁。引用C++14(N4140),[support.start.term]18.5/8(重点): 函数ex

请注意,没有
~A:3
,这意味着对象
a3
没有被破坏

然而,根据:

std::exit
导致正常程序终止。下面介绍了几个清理步骤 执行:

具有线程本地存储持续时间的对象的析构函数。。。是 保证会被叫来


这里的问题是,当您退出进程时,线程将(在大多数现代多任务操作系统上)被强制终止。线程的终止发生在操作系统级别,操作系统对对象或析构函数一无所知。

具有线程存储持续时间的对象保证仅对调用
退出的线程进行销毁。引用C++14(N4140),[support.start.term]18.5/8(重点):

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

  • 首先,销毁线程存储持续时间且与当前线程关联的对象。 接下来,通过调用atexit销毁具有静态存储持续时间的对象并注册函数 我们称之为。有关破坏和调用的顺序,请参见3.6.3。(不支持自动对象。) 由于调用
    exit()
    )而被销毁 如果控件离开由
    调用的已注册函数,则退出该函数,因为该函数不提供
    应调用抛出异常的处理程序std::terminate()
    (15.5.1)
  • 接下来,使用 刷新未写入的缓冲数据,关闭所有打开的C流,并通过调用创建所有文件
    tmpfile()
    已删除
  • 最后,将控件返回到主机环境。如果状态为零或退出成功,则 返回状态成功终止的实现定义表单。如果状态为退出失败,则返回状态未成功终止的实现定义形式。 否则,返回的状态是实现定义的

因此,该标准不保证销毁与调用
exit

的线程以外的其他线程关联的线程存储持续时间的对象,因为我想您“分离”了它。这是吗?否。即使线程没有分离,它也是一样的。@Synxis当然,假设所有析构函数只执行简单的内存管理,而不执行任何更复杂的操作。但是,不调用析构函数而退出会显式破坏
std::basic_fstream
的刷新保证(例如),因为销毁时刷新行为是由其成员
std::basic_filebuf
的析构函数引起的。通常,无法从外部干净地杀死线程。您的(或库,或编译器运行时)代码必须由线程本身调用(包括最后调用线程退出本身)。你必须为每个线程编写线程退出逻辑代码。这表明cppreference(在问题中引用)与C++规范不一致;它应该在该网站上报告为一个bug。@HansOlsson:cppreference.com是一个wiki,所以与其报告为bug,不如自己修复它(如果需要):-)对不起,但我认为这根本不能回答问题
std::exit
在退出流程之前进行一系列清理,这就是OP询问的清理。没有人希望在进程退出后调用析构函数。std::exit不是操作系统级函数或系统调用。它是C++标准库函数,因此它会知道C++语言构造。操作系统是否知道对象,或者是否有操作系统在运行,都是无关紧要的。
#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);
}
A:1
A:2
A:4
A:5
A:3
~A:5
~A:2
~A:4
~A:1
[[noreturn]] void exit(int status)