Ответ 1
Да, вы можете определенно использовать = default
для таких деструкторов. Особенно, если вы просто заменили его на {}
. Я думаю, что = default
лучше, потому что он более явный, поэтому он сразу бросается в глаза и не оставляет места для сомнений.
Однако при этом нужно учитывать несколько заметок.
Когда вы = default
деструктор в файле заголовка (см. править) (или любая другая специальная функция, если на то пошло), он в основном определяет его в заголовке. При разработке общей библиотеки вы можете явно указать деструктор, предоставляемый только библиотекой, а не в заголовке, чтобы вы могли легче изменить ее в будущем, не требуя пересоздания зависимого двоичного файла. Но опять же, когда вопрос заключается не только в = default
или {}
.
РЕДАКТИРОВАТЬ:. Как замечает Шон в комментариях, вы также можете использовать = default
вне декларации класса, который получает лучшее из обоих миров здесь.
Другим важным техническим различием является то, что стандарт говорит о том, что явно дефолтная функция, которая не может быть сгенерирована, просто не будет сгенерирована. Рассмотрим следующий пример:
struct A { ~A() = delete; };
struct B : A { ~B() {}; }
Это не скомпилировалось бы, поскольку вы вынуждаете компилятор генерировать указанный код (и его неявные реквизиты, такие как вызов деструктора) для деструктора B, и он не может, поскольку деструктор удален. Однако рассмотрим это:
struct A { ~A() = delete; };
struct B : A { ~B() = default; }
Это, по сути, будет компилироваться, потому что компилятор видит, что ~B()
не может быть сгенерирован, поэтому он просто не генерирует его - и объявляет его как удаленный. Это означает, что вы получите только ошибку, когда пытаетесь фактически использовать/вызывать B::~B()
.
Это, по крайней мере, два значения, о которых вы должны знать:
- Если вы хотите получить ошибку, просто компилируя что-либо, содержащее объявление класса, вы не получите его, так как оно технически корректно.
- Если вы изначально всегда используете
= default
для таких деструкторов, вам не придется беспокоиться о том, что удаляемый деструктор суперкласса удаляется, если он окажется в порядке, и вы никогда его не используете. Это своего рода экзотическое использование, но в этом смысле оно более корректно и надежно. Вы получите только ошибку, если вы действительно используете деструктор, иначе вы останетесь один.
Итак, если вы собираетесь использовать защитный подход к программированию, вам может потребоваться просто использовать {}
. В противном случае вы, вероятно, лучше = default
ing, так как это лучше соответствует минимальным программным инструкциям, необходимым для получения правильной рабочей базы и предотвращения непреднамеренных последствий 1.
Что касается = 0
: Да, это все еще правильный способ сделать это. Но учтите, что на самом деле он не указывает, что "нет реализации по умолчанию", а скорее, что (1) класс не является исполняемым; и (2) Любые производные классы должны переопределить эту функцию (хотя они могут использовать необязательную реализацию, предоставляемую суперклассом). Другими словами, вы можете определить функцию и объявить ее чистым виртуальным. Вот пример:
struct A { virtual ~A() = 0; }
A::~A() = default;
Это обеспечит эти ограничения для A (и его деструктора).
1) Хорошим примером того, почему это может быть полезно неожиданным образом, является то, как некоторые люди всегда использовали return
с круглыми скобками, а затем С++ 14 добавил decltype(auto)
, который по существу был создан техническая разница между его использованием и без круглых скобок.