Почему деструктор базового класса доступен только при объявлении пользовательского конструктора? - программирование
Подтвердить что ты не робот

Почему деструктор базового класса доступен только при объявлении пользовательского конструктора?

Comeau, g++ (ideone), и EDG принимает следующий код без диагностики. Visual С++ компилируется успешно, хотя и с предупреждением C4624.

class indestructible_base
{
  ~indestructible_base();
};

class T : indestructible_base
{
public:
  //T() {}
};

int main(void) { new T(); }

Раскомментируйте конструктор и он больше не компилируется.

Возможно, это правило, что если исключение возникает внутри конструктора, подобъекты должны быть уничтожены? Кажется странным, так как тело пустое и не может вызвать исключения. Тем не менее, добавьте проверку спецификации исключений для того, чтобы исключение не было выбрано (throw() или noexcept), и это не имеет никакого значения.

Почему конструктор, объявленный пользователем, требует доступа к деструктору базового класса, в то время как конструктор, созданный автоматически?

Этот вопрос был вдохновлен: Предотвращение запуска деструктора на С++

4b9b3361

Ответ 1

Я подозреваю, что это может быть поведение, специфичное для компилятора. Вот моя теория:

Поскольку (в данном конкретном случае) неявно определенный T() является тривиальным конструктором (как определено в стандарте 12.1 (5) стандарта), компилятор даже не пытается сгенерировать тело для T(). Поскольку нет тела ctor, исключений, которые могли бы быть созданы во время "строительства" (чего не было на самом деле), нет необходимости генерировать dtor-вызов, поэтому нет необходимости генерировать dtor-тело, только чтобы узнать, что базовый класс dtor является закрытым.

Но как только T() становится нетривиальным (даже если он остается неявным), необходимо создать тело ctor, и вы получите ошибку. Что-то простое, как добавление члена в класс T, который имеет определяемый пользователем конструктор, сделает неявно определенный T() стал нетривиальным.

Отдельная, но связанная проблема заключается в том, что new T() не генерирует вызов dtor (поскольку у вас нет соответствующего delete в любом месте). В отличие от этого, если я просто заменяю new T() на T dummy в вашем коде, тогда я получаю следующее из gcc, предлагая, что теперь он выполняет полную проверку доступности dtor (в результате необходимости генерации вызова dtor ):

test.cpp: In destructor 'T::~T()':
test.cpp:3: error: 'indestructible_base::~indestructible_base()' is private
test.cpp:7: error: within this context
test.cpp: In function 'int main()':
test.cpp:12: note: synthesized method 'T::~T()' first required here
test.cpp:12: warning: unused variable 'dummy'

Ответ 2

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

#include <string>

class indestructible_base
{
  ~indestructible_base();
  std::string s; // <------ this may throw
};

class T : indestructible_base
{
public:
  //T() {}
};

int main(void) { new T(); }

Итак, я думаю, что исключения - это ответ. В ANSI ISO IEC 14882 единственным конструктором строк noexcept(true) является конструктор перемещения. Я считаю, этот должен компилироваться, но ideone говорит "нет".