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

时间:2018-05-16 19:53:04

标签: c++ language-lawyer static-initialization atexit initialization-order

cppreference说std::atexit

  

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

之间的顺序

我理解这段话意味着,如果在静态初始化期间调用std::atexit,则在破坏静态对象之前将调用已注册的函数,该静态对象在上次初始化时静态对象被破坏。注册该函数的{1}}被调用。我还解释“可以同时调用”来表示静态对象析构之间可能发生的调用,而不是对单词的多线程解释。

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

std::atexit

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

#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;
}

这让我相信ctor dtor atexit 在构造完成之前不会被认为是在这种情况下被初始化的。换句话说,该函数被认为是在my_foo初始化之前注册的,因此注册函数在my_foo被破坏后执行。

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

1 个答案:

答案 0 :(得分:7)

对析构函数的调用将在调用传递给atexit的函数之前发生。来自[basic.start.term],第5页:

  

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