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

Статический экземпляр элемента шаблона С++

#include <map>
#include <iostream>
template <typename T>
class A 
{
 static std::map<int, int> data;
public:
 A()
 {
  std::cout << data.size() << std::endl;
  data[3] = 4;
 }
};

template <typename T>
std::map<int, int> A<T>::data;

//std::map<int, int> A<char>::data;

A<char> a;

int main()
{
 return 0;
}

Что не так с этим? Без явного инстанцирования он разбивается на

 data[3] = 4; 
Явное создание экземпляра решает проблему, но программа прерывается после
std::cout << data.size() << std::endl;
, что означает, что был создан экземпляр шаблона статического класса data.
4b9b3361

Ответ 1

В вашем коде нет явного экземпляра.

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

См. Инициализация статического члена С++.

Ответ 2

У меня нет Visual С++, но я вижу ту же проблему с компиляцией кода с GCC. Вам необходимо инициализировать элемент данных:

template<> std::map<int, int> A<char>::data = std::map<int, int>();

С этим изменением он компилируется и работает правильно (для меня в GCC на Linux).

Ответ 3

В этом коде есть несколько ошибок. Сначала первоначальная идея не очень хорошая. У вас есть два глобальных статических объекта: a и A::data. Порядок их инициализации - undefined. В зависимости от настроения вашего компилятора у вас есть 50% -ный шанс сначала создать конструктор a и попытаться записать что-то в неинициализированный A::data.

Это иногда называют проблемой статической инициализации порядка фиаско. Предлагаемое решение состоит в том, чтобы превратить такие объекты в локальные статические объекты, переместив их в функции:

#include <map>
#include <iostream>

template <typename T>
class A
{
  std::map<int, int> &data()
  {
    static std::map<int, int> d;
    return d;
  }
public:
  A()
  {
    std::cout << data().size() << std::endl;
    data()[3] = 4;
  }
};

int main()
{
  A<char> a;
  return 0;
}

Локальные статические объекты инициализируются при первом вызове функции.

О прокомментированном "явном экземпляре" вы забыли template <>.

Но после того, как вы префикс этой строки с template <>, это еще не определение, а объявление. Он объявляет, что определение A:: data в другом месте. Чтобы определить его, вам нужно что-то инициализировать, см., Например, ответ Джека Ллойда.