Ошибка создания экземпляра рекурсивного шаблона превышена в dtor, но не в ctor. Почему?

#c #templates

Вопрос:

Попробуйте clang и g , тот же результат для обоих.
fatal error: recursive template instantiation exceeded maximum depth

 template<class T>
struct Bar {
  ~Bar() {
    if (ptr) { delete ptr; }
  }
  Bar<Bar<T>> * ptr{nullptr};
};

int main() { Bar<void> obj; }
 

Но версия ctor компилируется без ошибок:

 template<class T>
struct Bar {
  Bar() {
    if (ptr) { delete ptr; }
  }
  Bar<Bar<T>> * ptr{nullptr};
};

int main() { Bar<void> obj; }
 

В чем проблема с версией dtor?

Комментарии:

1. Это не решает вопроса, но вам не нужно проверять, является ли указатель нулевым, прежде чем удалять его. delete правильно обрабатывает нулевые указатели.

Ответ №1:

В чем проблема с версией dtor?

Подумайте о том, что Bar<void> obj; означает подобное заявление.

Этот объект должен иметь свой деструктор, вызываемый при main возврате. Таким образом, деструктор ~Bar<void> будет создан.

Что содержит созданный экземпляр деструктора? delete Выражение лица. Вы можете возразить, что он проходит проверку на недействительность и поэтому никогда не будет выполнен, но это не имеет значения. Код C разрешен статически и должен быть корректным, даже если компилятор может устранить мертвый код.

Это delete выражение должно будет вызвать деструктор Bar<Bar<void>> , и поэтому оно должно быть создано… Промойте и повторите.

С другой стороны, в версии конструктора у вас есть тривиальный деструктор. Он ничего не делает и, конечно, не нуждается в создании экземпляра какого-либо другого типа. Поэтому он отлично компилируется, когда конструктор должен создать его экземпляр.