Я пытаюсь понять правила секвенирования для инициализации и уничтожения объектов области имен и области действия со статической продолжительностью хранения и продолжительностью локального хранилища в контексте основного потока.Рассмотрим эти два класса:
struct Foo {
Foo() { std::cout << "Foo\n"; }
~Foo() { std::cout << "~Foo\n"; }
static Foo &instance();
};
struct Bar {
Bar() { std::cout << "Bar\n"; }
~Bar() { std::cout << "~Bar\n"; }
static Bar &instance();
};
Они идентичны, за исключением реализаций их статических функций-членов instance
:
thread_local Foo t_foo;
Foo &Foo::instance() { return t_foo; }
Bar &Bar::instance() { static Bar s_bar; return s_bar; }
Bar
- это синглтон Мейерса, блок-объект области действия со статической продолжительностью хранения.
Foo
- это объект области имен пространства имен с продолжительностью локального хранения потока.
Теперь функция main
:
int main() {
Bar::instance();
Foo::instance();
}
Вот вывод из GCC 8.1.0 и Clang 5.0.0:
Bar
Foo
~Foo
~Bar
Попробуйте его вживую: https://coliru.stacked -crooked.com / a / f83a9ec588aed921
Я ожидал, что сначала будет создан Foo
, потому что он находится в области имен.Я предполагаю, что реализация может отложить инициализацию до первого использования объекта.Я не знал, что это может быть отложено до инициализации статической области блока, но я могу с этим смириться.
Теперь я изменил порядок вызовов функций в main
:
int main() {
Foo::instance();
Bar::instance();
}
А вот вывод:
Foo
Bar
~Foo
~Bar
Теперь я перенес первое использование odr экземпляра Foo
до первого вызова Bar::instance
, и порядокинициализация, как я и ожидал.
Но я думал, что объекты должны быть уничтожены в обратном порядке их инициализации, которая, как представляется, не происходит.Чего мне не хватает?
В отношении инициализации и уничтожения объектов статической и локальной потоковой памяти, cppreference и стандарта говорят такие вещи, как «когда запускается программа», «когда запускается поток»,«когда заканчивается программа» и «когда заканчивается поток», но как эти понятия связаны друг с другом в контексте основного потока?Или, если быть более точным, первый поток и последний поток?
В моей "реальной" проблеме Foo
(локальный поток) используется регистратором и деструктором базового классаBar
использует логгер, так что это фиаско статического порядка уничтоженияДругие потоки создаются, но Bar
(синглтон Мейерса) создается и уничтожается в основном потоке.Если бы я мог понять правила последовательности, то я мог бы попытаться решить «реальную» проблему, не прибегая к случайным попыткам.