Стандарт не распространяется на этот случай; самым строгим чтением будет то, что законно инициализировать thread_local
в деструкторе объекта со статической продолжительностью хранения, но незаконно разрешить программе продолжать нормальное завершение.
Проблема возникает в [basic.start.term]:
1 - деструкторы ([class.dtor]) для инициализированных объектов (то есть, те объекты, срок службы ([basic.life]) началось) со статической продолжительностью хранения вызываются в результате возврата из main и в результате вызова std :: exit ([support.start.term]). Деструкторы для инициализированных объектов с длительностью хранения потока в заданном потоке вызываются в результате возврата из исходной функции этого потока и в результате этого потока, вызывающего std :: exit. По завершении деструкторов для всех инициализированных объектов с длительностью хранения потоков в этом потоке секвенируются перед началом деструктора любого объекта со статической продолжительностью хранения. [...]
Так завершение bar::~Bar::foo::~Foo
секвенировали до начала bar::~Bar
, что является противоречием.
только получить выход может быть утверждать, что [basic.start.term]/1 применяется только к объектам, время жизни которых началось в момент окончания программы/нить, но против[stmt.dcl] имеет:
5 - Деструктор для объекта с объемной областью со статическими или потоковыми хранилищами будет выполняться тогда и только тогда, когда он был создан. [Примечание: [basic.start.term] описывает порядок, в котором уничтожаются объекты области области с статикой и продолжительностью хранения потоков. - конец примечание]
Это явно предназначено для применения только к нормальной нити и завершению программы, по возвращению из основных или из функции потока, или позвонив по телефону std::exit
.
Кроме того, есть [basic.stc.thread]:
Переменная с длительностью хранения нити должны быть инициализированы перед первым ODR использования ([basic.def.odr]), и, если построено, должно быть уничтожено на выходе резьбы ,
Здесь «инструкция» должна быть инструкцией для разработчика, а не для пользователя.
Обратите внимание, что нет ничего плохого в том, чтобы начать с жизни thread_local
, так как [basic.start.term]/2 не применяется (он ранее не был уничтожен). Вот почему я считаю, что неопределенное поведение происходит, когда вы разрешаете программе продолжать нормальное завершение.
Аналогичные вопросы задавали раньше, хотя о статической и статической длительности хранения, а не thread_local
против статики; Destruction of objects with static storage duration (и https://groups.google.com/forum/#!topic/comp.std.c++/Tunyu2IJ6w0), и Destructor of a static object constructed within the destructor of another static object. Я склонен согласиться с Джеймсом Канзе на последнем вопросе, что здесь применяется [defns.undefined], и поведение не определено, поскольку стандарт не определяет его. Лучшим способом продвижения было бы для кого-то, кто стоял, чтобы открыть отчет о дефекте (охватывающий все комбинации static
s и thread_local
s, инициализированные в деструкторах static
и thread_local
с), чтобы надеяться на окончательный ответ.
юридический или нет, зачем вам это делать? –
@DavidHaim Я пытаюсь реализовать часть 'libC++ abi' (' __cxa_thread_atexit() 'в частности), и мне было любопытно, должен ли я обрабатывать этот случай или нет. –
Это, вероятно, просто 'cout' уничтожается до' foo'. Попробуйте выбросить исключение из деструктора 'Foo' и посмотреть, вызывается ли' std :: terminate'. –