首先调用什么:静态对象的析构函数或 atexit 处理程序?

iva*_*nys 5 c++ destructor atexit

这种情况下订单是保证的还是UB的?

#include <iostream>
#include <cassert>

using namespace std;

struct TraceHelper
{
    TraceHelper()
    {
        cout << "TraceHelper::constructor()" << endl;
    }

    ~TraceHelper()
    {
        cout << "TraceHelper::destructor()" << endl;
    }
};

void trace_fn()
{
    static TraceHelper th;
    cout << "trace_fn()" << endl;
}

void my_atexit()
{
    cout << "my_atexit()" << endl;
}

int main()
{
    cout << "Entered main()" << endl;
    assert(0 == atexit(my_atexit));
    trace_fn();
    trace_fn();
    cout << "Exiting main()" << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

#include <iostream>
#include <cassert>

using namespace std;

struct TraceHelper
{
    TraceHelper()
    {
        cout << "TraceHelper::constructor()" << endl;
    }

    ~TraceHelper()
    {
        cout << "TraceHelper::destructor()" << endl;
    }
};

void trace_fn()
{
    static TraceHelper th;
    cout << "trace_fn()" << endl;
}

void my_atexit()
{
    cout << "my_atexit()" << endl;
}

int main()
{
    cout << "Entered main()" << endl;
    assert(0 == atexit(my_atexit));
    trace_fn();
    trace_fn();
    cout << "Exiting main()" << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

har*_*nan 2

我们在这里看到的是 main 函数和std::exit之间的交互:

\n
\n

从主函数返回,[...] 执行正常的函数终止(调用具有自动存储持续时间的变量的析构函数),然后执行 std::exit,传递 return 语句的参数(或 xe2 \x80\x8b0\xe2\x80\x8b(如果使用隐式返回)as\nexit_code。

\n
\n

就静态对象的销毁而言,与问题相关的是以下几行:

\n
\n

如果静态对象 A 的初始化完成是在调用某个函数 F 的 std::atexit 之前排序的,则终止期间对 F 的调用是在 A 的析构开始之前排序的。

\n

如果对某些函数 F 的 std::atexit 的调用被排序在静态对象 A 的初始化完成之前,则 A 的销毁开始被排序在终止期间对 F 的调用之前。

\n
\n

在问题的代码中,在函数中创建静态对象之前my_atexit()使用注册了该函数。因此,析构函数的调用发生在调用 之前。该行为符合预期。std::atexit()thtrace_fn()TraceHelpermy_atexit()

\n