从全局对象的构造函数调用时的std :: atexit排序

Fra*_*eux 8 c++ atexit initialization-order static-initialization language-lawyer

cppreference说std::atexit:

这些函数可以与具有静态存储持续时间的对象的销毁同时被调用,并且保持如果在B的注册之前如果A的注册被排序,则在调用之前对B的调用进行排序的保证. A,同样适用于静态对象构造函数和对atexit的调用之间的顺序

我理解这一段意味着,如果std::atexit在静态初始化期间调用,则在静态对象的销毁过程中,在静态对象被破坏之前调用已注册的函数,该静态对象std::atexit在调用注册函数时被最后初始化.我还解释"可以同时调用"意味着调用可以发生在静态对象析构之间,而不是对单词的多线程解释.

我想知道的是,当初始化开始或完成时,对象是否被视为已初始化(在此排序的上下文中).我写了一个简短的测试来测试这个:

#include <cstdlib>
#include <iostream>

struct foo
{
    foo() 
    {
        std::cout << "ctor\n";
        std::atexit([]() { std::cout << "atexit\n"; });
    }
    ~foo()
    {
        std::cout << "dtor\n";
    }
};

foo my_foo;

int main()
{
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我得到的输出是(http://cpp.sh/3bllu):

ctor
dtor
atexit
Run Code Online (Sandbox Code Playgroud)

这使我相信,my_foo在构建完成之前,不会在这种情况下初始化.换句话说,该函数被认为在my_foo初始化之前已经注册,因此注册函数在my_foo销毁之后执行.

我似乎找不到任何可以保证这种行为的东西,我甚至不完全确定我对引用段落的初步解释是正确的.我描述的行为是我可以依赖的,还是实现定义甚至未定义的行为?

120*_*arm 7

对函数的调用将在传递给函数的调用之前发生atexit.从[basic.start.term],p5:

如果std::atexit在具有静态存储持续时间的对象的初始化完成之前强烈地发生调用,则在调用传递给函数的函数之前对对象的析构函数的调用进行排序std::atexit.