Переменные шаблона безопасны для потока? они размещены в сегменте данных?

Я играю с новой функцией шаблонных переменных из C++14, чтобы привыкнуть к ней (возможно, скоро это сделают, потому что кажется, что некоторые компиляторы не реализовали ее полностью).

Теперь мне интересно, где лежит каждый экземпляр переменной шаблона. В тестах, которые я делал до сих пор, они кажутся инициализированными перед любыми статическими данными, поэтому мне интересно, помещены ли они в сегмент данных программы. Давайте посмотрим, что я пробовал до сих пор, у меня есть класс, который печатает информацию о строительстве и разрушении:

struct squealer
{
    squealer(std::string a_name) : m_name(a_name) { std::cout << this << ' ' << m_name << ' ' << __PRETTY_FUNCTION__ << '\n'; }
    ~squealer() { std::cout << this << ' ' << m_name << ' ' << __PRETTY_FUNCTION__ << '\n'; }
    void f() {}
    const std::string m_name;
};

И программа, которая создает некоторые squealer Программа находится в локальном хранилище, в статическом хранилище и в качестве переменных шаблона:

// static storage squealer
squealer s("\"static\"");

// template variable squealer
template <int i> squealer test(std::string(i, 'A'));

// function using a template variable squealer
void f() { test<1>.f(); }

int main(int argc, char **argv)
{
    // local storage squealer
    squealer ss("local");

    // using another template variable squealers
    test<2>.f();
    switch (argc)
    {
        case 1: test<3>.f(); break;
        case 2: test<4>.f(); break;
        case 3: test<5>.f(); break;
        case 4: test<6>.f(); break;
    }

    return 0;
}

Вот программа, и это вывод:

A squealer::squealer(std::string)
AA squealer::squealer(std::string)
AAA squealer::squealer(std::string)
AAAA squealer::squealer(std::string)
AAAAA squealer::squealer(std::string)
AAAAAA squealer::squealer(std::string)
"static" squealer::squealer(std::string)
local squealer::squealer(std::string)
local squealer::~squealer()
"static" squealer::~squealer()
AAAAAA squealer::~squealer()
AAAAA squealer::~squealer()
AAAA squealer::~squealer()
AAA squealer::~squealer()
AA squealer::~squealer()
A squealer::~squealer()

Как мы видим, все переменные шаблона squealer экземпляры создаются до того, как названный "static" и в конце (как и ожидалось) тот, названный local создается, порядок уничтожения противоположен (как и ожидалось), поэтому: порядок создания / инициализации экземпляров шаблонных переменных совпадает с его появлением в коде независимо от локальности этого появления и независимо от того, используются они или нет (f() функция никогда не вызывается).

Итак, первый вопрос: размещены ли переменные этого шаблона в сегменте данных? Я не знаю, как это проверить или проверить.

Второй вопрос, все ли это переменные шаблона squealer экземпляры потокобезопасны? Я n3376 прочитал §6.7 следующего предложения (выделение мое):

Реализации разрешается выполнять раннюю инициализацию других переменных области блока со статической или продолжительностью хранения потока при тех же условиях, в которых реализации разрешается статически инициализировать переменную со статической или продолжительностью хранения потока в области пространства имен (3.6.2). В противном случае такая переменная инициализируется при первом прохождении контроля через ее объявление; такая переменная считается инициализированной после завершения ее инициализации. Если инициализация завершается выдачей исключения, инициализация не завершена, поэтому она будет повторена при следующем входе элемента управления в объявление. Если элемент управления вводит объявление одновременно во время инициализации переменной, параллельное выполнение должно ожидать завершения инициализации.

Из C++11, если все переменные шаблона squealer экземпляры находятся в статическом хранилище, они должны быть безопасными для потоков, не так ли?

Благодарю.

2 ответа

Решение

В разделе стандарта, который вы цитируете, описаны переменные области блока со статической продолжительностью хранения, например:

int foo() {
  static int bar = 42;
  return bar;
}

из которых ваша программа не имеет ни одного. Все ваши переменные со статической продолжительностью хранения объявляются в области имен, поэтому вам нужно посмотреть на [basic.start.init] (3.6.2). В частности, абзац второй, в котором говорится:

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

...

Динамическая инициализация нелокальной переменной со статической длительностью хранения неупорядочена, если переменная является неявно или явно созданной специализацией, а в противном случае упорядочена [ Примечание: явно специализированный элемент статических данных или специализация шаблона переменной имеет упорядоченную инициализацию. -примечание к концу ] Переменные с упорядоченной инициализацией, определенной в одной единице перевода, должны быть инициализированы в порядке их определений в единице перевода. Если программа запускает поток (30.3), последующая инициализация переменной не является последовательной по отношению к инициализации переменной, определенной в другой единице перевода. В противном случае инициализация переменной выполняется неопределенным образом по отношению к инициализации переменной, определенной в другой единице перевода. Если программа запускает поток, последующая неупорядоченная инициализация переменной не секвенируется относительно любой другой динамической инициализации. В противном случае неупорядоченная инициализация переменной определяется неопределенным образом относительно любой другой динамической инициализации.

В программе вопроса все squealer экземпляры со статической продолжительностью хранения должны быть динамически инициализированы, поскольку squealer имеет члена std::string это не может быть с постоянной инициализацией. ::s заказал инициализацию, и все экземпляры test имеют неупорядоченную инициализацию, поскольку каждая из них является "явно или неявно конкретизированной специализацией" шаблона test, test экземпляры гарантированно инициализируются перед вводом main, но в противном случае все ставки отключены: они могут быть инициализированы в любом порядке, возможно, до и / или после инициализации ::s и что более важно std::cout, Эти инициализации, в частности, не являются поточно-ориентированными: "Если программа запускает поток, последующая неупорядоченная инициализация переменной не выполняется по последовательности для любой другой динамической инициализации".

Специализации шаблонов переменных являются статическими переменными, как указано в [temp.inst]/12:

Неявно созданные экземпляры шаблонов классов, функций и переменных помещаются в пространство имен, в котором определен шаблон.

Поэтому применяются обычные статические правила инициализации, что означает, что все специализации инициализируются до main() выполняет.

Другие вопросы по тегам