В моем проекте мне нужно отдельное локальное хранилище для каждого экземпляра элемента данных.Поскольку при реализации этой функции у меня возникли проблемы, я извлек упрощенную версию кода в следующую программу на C ++ 14:
#include <iostream>
#include <unordered_map>
#include <vector>
template<class T> class ThreadLocalMember
{
public:
T& local() { return store.map[this]; }
private:
struct Store
{
Store() { std::cout << "construct" << std::endl; }
~Store() { std::cout << "destruct" << std::endl; }
std::unordered_map<ThreadLocalMember<T>*, T> map;
};
static thread_local Store store;
};
template <class T> thread_local typename ThreadLocalMember<T>::Store ThreadLocalMember<T>::store;
int main()
{
ThreadLocalMember<int> counter;
std::cout << "point 1" << std::endl;
int result = counter.local();
std::cout << "point 2; result: " << result << std::endl;
return result;
}
Ожидаемый результат -
point 1
construct
point 2; result: 0
destruct
Однакопри компиляции с помощью clang Apple LLVM версии 9.1.0 (clang-902.0.39.1) на MacOS High Sierra 10.13.4 с использованием
clang++ -std=c++14 -O3 ThreadLocalMember.cpp -o test
(или с -O1
или -O2
) вывод будет:
point 1
Illegal instruction: 4
Кажется, что конструктор переменной thread_local никогда не выполняется, и программа аварийно завершает работу при первом обращении к переменной.
Проблема исчезает, когда
- программа компилируется без оптимизации (что недопустимо в производственном режиме)
- класс шаблона заменяется обычным классом (возможный обходной путь, но очень раздражающий)
- ключевое слово thread_localудалены в обоих местах (но тогда программа больше не делает то, что мне нужно, когда есть несколько потоков)
Программа также компилирует и запускает fКроме того, при использовании gcc 5.4.0 в Ubuntu 16 с флагом оптимизации или без него.
Что-то не так с моим кодом или я вижу ошибку компилятора clang?