Stati c члены специализаций шаблонных классов имеют неупорядоченную dynamici c инициализацию, что означает, что нет никакой гарантии, в каком порядке они будут инициализированы относительно других динамических c инициализаций.
Если A<int>::l
инициализируется после temp
, то при инициализации temp
будет пытаться получить доступ к A<int>::l
до того, как началось его время жизни, что приведет к неопределенному поведению.
Обычным решением этого является поместите переменную stati c в функцию stati c и вызовите ее вместо этого. Локальные переменные stati c инициализируются, когда выполнение достигает своего объявления в первый раз, поэтому они всегда правильно упорядочены.
template<typename T>
class A
{
public:
static auto& l() {
static std::list<A<T>*> instance;
return instance;
}
A( T t ) : val( t ) { l().push_back( this ); }
~A() { l().remove( this ); }
T val;
void print() { std::cout << val; }
};
Однако следует избегать глобальных переменных const
как можно больше в первое место. Они обычно усложняют рассуждения о коде и имеют такие проблемы, как порядок инициализации здесь.
Я не знаю, какова цель списка экземпляров здесь, но у него есть похожие проблемы, и его, вероятно, следует избегать, если возможный. Кроме того, он будет иметь довольно плохую производительность, особенно если у вас много экземпляров A<T>
, потому что l.remove( this );
будет занимать линейное время в количестве элементов в списке. Попробуйте использовать std::set
или std::unordered_set
вместо std::list
.
Дополнительные примечания:
Тип возврата main
must быть int
в C ++. void
, поскольку возвращаемый тип является нестандартным расширением некоторых компиляторов.
Ваш класс нарушает правило 0/3/5 . Вам нужно определить конструктор копирования и перемещения и оператор присваивания с правильной семантикой, иначе ваш список экземпляров не будет содержать все экземпляры, когда ваш класс копируется.
Возможно, вы также захотите сохранить const A<T>*
вместо A<T>*
в списке. Последнее опасно. Если вы когда-нибудь объявите переменную типа const A<T>
, то указатель, который вы сохраните в списке, все равно будет не const
. Если вы затем используете указатель из списка для изменения объекта, вы не будете предупреждены о том, что пытаетесь изменить объект const
(что вызывает неопределенное поведение).