Упорядочение std::atexit при вызове из конструктора глобального объекта

cppreference говорит о std::atexit:

Функции могут вызываться одновременно с уничтожением объектов со статической продолжительностью хранения и друг с другом, сохраняя гарантию того, что если последовательность A была упорядочена до регистрации B, то вызов B упорядочен до вызова А, то же самое относится к последовательности между конструкторами статических объектов и вызовами 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;
}

Вывод, который я получаю ( http://cpp.sh/3bllu):

ctor
dtor
atexit

Это заставляет меня верить, что my_foo не считается инициализированным в этом контексте, пока не завершится его построение. Другими словами, функция считается зарегистрированной ранее my_foo была инициализирована, поэтому зарегистрированная функция выполняется после my_foo Разрушение

Кажется, я не могу найти ничего, что гарантировало бы такое поведение, и я даже не совсем уверен, что моя первоначальная интерпретация процитированного отрывка верна. Является ли описанное мной поведение чем-то, на что я могу положиться, или это определенная реализация или даже неопределенное поведение?

1 ответ

Решение

Вызов деструктора произойдет до того, как вызов функции будет передан atexit, Из [basic.start.term], стр. 5:

Если звонок в std::atexit если до завершения инициализации объекта со статической длительностью хранения происходит сильный вызов, то вызов деструктора для объекта упорядочивается до того, как вызов функции передается std::atexit,

Другие вопросы по тегам