Когда инициализируется глобальная переменная `thread_local`?

Рассмотрим следующий пример (блокировка защиты на cout опущена для простоты).

#include <future>
#include <iostream>
#include <thread>

using namespace std;

struct C
{
  C() { cout << "C constructor\n";}
  ~C() { cout << "C destructor\n";}
};

thread_local C foo;

int main()
{
   int select;
   cin >> select;
   future<void> f[10];
   for ( int i = 0;i < 10; ++i)
       f[i] = async( launch::async,[&](){ if (select) foo; } );
   return 0;
}

В обоих случаях clang и gcc эта программа ничего не выводит, если пользователь пишет "0", в то время как он печатает Constructor/Destructor 10 раз, если пользователь вводит ненулевой номер. Кроме того, clang жалуется на очевидный результат неиспользованного выражения.

Поскольку срок службы thread_local должен охватывать весь ресурс, я ожидал, что переменная foo будет инициализирована в каждом потоке независимо от ввода пользователя.

Мне может понадобиться переменная thread-local с единственной целью иметь побочный эффект в конструкторе, соответствует ли стандартное требование инициализации объекта thread_local при его первом использовании?

Ответ 1

Стандарт допускает такое поведение, хотя оно не гарантирует его. Из 3.7.2/2 [basic.stc.thread]:

Переменная с длительностью хранения потока должна быть инициализирована до его первое использование odr (3.2) и, если оно построено, должно быть уничтожено на выход потока.

Также возможно, что объекты создаются в какой-то другой момент (например, при запуске программы), так как "перед первым использованием" означает "в любой точке до тех пор, пока она есть до", а не "непосредственно перед".