Подтвердить что ты не робот

С++ 11: GCC 4.8 static thread_local std:: unique_ptr undefined ссылка

Мне нужно сохранить уникальный указатель для каждого потока, к которому будет обращаться макрос. Я думал, что должен решить это с помощью одноэлементных и статических объектов thread_local std:: unique_ptr. Вот упрощенная версия кода:

main.cpp

#include <thread>
#include <vector>
#include <iostream>
#include <mutex>
using namespace std;

#include "yay.hpp"

mutex coutMutex;

void yay(int id)
{
    int* yayPtr = getYay();

    // I know this is bad
    coutMutex.lock();
    cout << "Yay nr. " << id << " address: " << yayPtr << endl;
    coutMutex.unlock();
}

int main()
{
    vector<thread> happy;
    for(int i = 0; i < thread::hardware_concurrency(); i++)
    {
        happy.push_back(thread(yay, i));
    }

    for(auto& smile : happy)
    {
        smile.join();
    }
    return 0;
}

yay.hpp

#ifndef BE_HAPPY
#define BE_HAPPY

#include <memory>
class Yay
{
    private:
        static thread_local std::unique_ptr<int> yay;
        Yay() = delete;
        Yay(const Yay&) = delete;
        ~Yay() {}
    public:
        static int* getYay()
        {
            if(!yay.get())
            {
                yay.reset(new int);
            }
            return yay.get();
        }
};

#define getYay() Yay::getYay()

#endif

yay.cpp

#include "yay.hpp"

thread_local std::unique_ptr<int>  Yay::yay = nullptr;

Если я скомпилирую это с помощью gcc 4.8.1:

g++ -std=c++11 -pthread -o yay main.cpp yay.cpp

Я получаю:

/tmp/cceSigGT.o: In function `_ZTWN3Yay3yayE':
main.cpp:(.text._ZTWN3Yay3yayE[_ZTWN3Yay3yayE]+0x5): undefined reference to `_ZTHN3Yay3yayE'
collect2: error: ld returned 1 exit status

Я надеялся, что могу получить больше информации от clang, однако он отлично работает с clang 3.4:

clang++ -std=c++11 -pthread -o yay main.cpp yay.cpp

И запуск программы дает результат, который я ожидал:

Yay nr. 2 address: 0x7fcd780008e0
Yay nr. 0 address: 0x7fcd880008e0
Yay nr. 1 address: 0x7fcd800008e0
Yay nr. 3 address: 0x7fcd700008e0
Yay nr. 4 address: 0x7fcd740008e0
Yay nr. 5 address: 0x7fcd680008e0
Yay nr. 6 address: 0x7fcd6c0008e0
Yay nr. 7 address: 0x7fcd600008e0

Я не уверен, что я делаю неправильно здесь, не возможно ли иметь статические объекты thread_local unique_ptr? Он работает с простыми типами, такими как int или "голые" указатели.

Изменить:

Возможно, это ошибка, связанная с http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55800

Edit2:

Обходной путь 1: скомпилируйте один файл с помощью clang (yay.cpp)

Обходной путь 2 (ужасный и неспортивный): сначала скомпилируйте yay.cpp для сборки, добавьте

.globl _ZTWN3Yay3yayE
_ZTWN3Yay3yayE = __tls_init

в файл сборки, скомпилировать в файл объекта, ссылку на остальные

4b9b3361

Ответ 1

Я экспериментировал с этим, определяя do-nothing ctor для Yay в Yay.hpp:

- Yay() = delete;
+ Yay() {}

Когда я это сделал, сообщение об ошибке стало:

/tmp/cc8gDxIg.o: In function `TLS wrapper function for Yay::yay':
main.cpp:(.text._ZTWN3Yay3yayE[_ZTWN3Yay3yayE]+0x5): undefined reference to `TLS init function for Yay::yay'

Это привело меня к ошибке GCC 55800. Ошибка существует в версиях GCC до 4.8.2 и исправлена ​​в 4.8.3 и 4.9. В обсуждениях, которые я нашел в двух экземплярах ошибка GCC 59364, было принято решение не возвращать исправление порта. Таким образом, ваш ассемблерный взлом оказывается единственным доступным решением, пока вы не перейдете на 4.9.