В следующем примере программы используется переменная локального шаблона потока и создается ее экземпляр с использованием типа в анонимном пространстве имен. Это приводит к ошибке компоновщика в gcc
. В clang
он на самом деле компилируется, но не работает правильно.
#include <stdio.h>
template<typename T>
struct container {
container() { printf("construct: %p\n", this); }
~container() { printf("destruct: %p\n", this); }
};
template<typename T>
thread_local container<T> storage;
namespace {
struct bar {};
}
int main() {
auto& ref1 = storage<bar>;
auto& ref2 = storage<bar>;
}
На gcc это завершается с ошибкой ссылки:
a.cpp:6:2: warning: ‘container<T>::~container() noexcept [with T = {anonymous}::bar]’ used but never defined
~container() { printf("destruct: %p\n", this); }
^
/tmp/ccgh0P15.o: In function `__tls_init':
a.cpp:(.text+0xa9): undefined reference to `container<(anonymous namespace)::bar>::~container()'
С помощью clang программа компилируется, но выдает очень тревожный вывод:
construct: 0x7fb8d1c003d0
construct: 0x7fb8d1c003d0
destruct: 0x7fb8d1c003d0
destruct: 0x7fb8d1c003d0
Есть ли некоторые неровности вокруг thread_local / шаблонных переменных, с которыми я здесь сталкиваюсь? Мне неясно, почему это когда-либо приведет к ошибке ссылки (ошибка ссылки исчезнет, если я удалю thread_local). В случае clang, как двойное уничтожение объекта со статической продолжительностью хранения может быть чем угодно, только не ошибкой компилятора? В clang проблема исчезает, если я удаляю анонимное пространство имен ИЛИ спецификацию thread_local ИЛИ, удаляя одну из ссылок в main ().
Может кто-нибудь пролить свет на это, мне в основном просто любопытно, если я что-то неправильно понимаю. Спасибо!
EDIT:
clang++ -v
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
g++ -v
gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)