Я первоначально разместил это как вопрос только о деструкторах, но теперь я добавляю рассмотрение конструктора по умолчанию. Вот оригинальный вопрос:
Если я хочу дать моему классу деструктор, который является виртуальным, но в остальном такой же, как и тот, который генерирует компилятор, я могу использовать
=default
:class Widget { public: virtual ~Widget() = default; };
Но кажется, что я могу получить тот же эффект с меньшим количеством печати, используя пустое определение:
class Widget { public: virtual ~Widget() {} };
Есть ли способ, по которому эти два определения ведут себя по-разному?
Судя по ответам на этот вопрос, ситуация для конструктора по умолчанию выглядит аналогично. Учитывая, что для деструкторов почти нет различий в значении между " =default
" и " {}
", существует ли аналогичное различие в значении между этими опциями для конструкторов по умолчанию? То есть, если я хочу создать тип, в котором объекты этого типа будут создаваться и уничтожаться, почему я хочу сказать
Widget() = default;
вместо того
Widget() {}
?
Я прошу прощения, если расширение этого вопроса после первоначальной публикации нарушает некоторые правила SO. Размещение почти идентичного вопроса для конструкторов по умолчанию показалось мне менее желательным вариантом.
источник
= default
это более явно imo и согласуется с поддержкой его конструкторами.std::has_trivial_destructor<Widget>::value
иtrue
для первого, ноfalse
для второго. Что это значит, я тоже не знаю. :)Ответы:
Это совершенно другой вопрос, когда мы спрашиваем о конструкторах, а не о деструкторах.
Если ваш деструктор
virtual
, то разница незначительна, как отметил Говард . Однако, если ваш деструктор не виртуален , это совсем другая история. То же самое верно и для конструкторов.Использование
= default
синтаксиса для специальных функций-членов (конструктор по умолчанию, конструкторы / назначения копирования / перемещения, деструкторы и т. Д.) Означает нечто очень отличное от простого выполнения{}
. С последним функция становится «предоставленной пользователем». И это все меняет.Это тривиальный класс по определению C ++ 11:
Если вы попытаетесь создать его по умолчанию, компилятор автоматически сгенерирует конструктор по умолчанию. То же самое касается копирования / перемещения и разрушения. Поскольку пользователь не предоставил ни одну из этих функций-членов, спецификация C ++ 11 считает это «тривиальным» классом. Поэтому это законно, например, memcpy их содержимое вокруг, чтобы инициализировать их и так далее.
Это:
Как следует из названия, это уже не тривиально. Он имеет конструктор по умолчанию, предоставленный пользователем. Неважно, если он пуст; Что касается правил C ++ 11, то это не может быть тривиальным типом.
Это:
Опять же, как следует из названия, это тривиальный тип. Зачем? Потому что вы сказали компилятору автоматически генерировать конструктор по умолчанию. Следовательно, конструктор не "предоставляется пользователем". И, следовательно, тип считается тривиальным, поскольку у него нет предоставленного пользователем конструктора по умолчанию.
= default
Синтаксис в основном там делать такие вещи , как конструкторы копирования / присваивание, когда вы добавляете функции - членов , которые препятствуют созданию таких функций. Но он также запускает специальное поведение компилятора, поэтому он полезен и для конструкторов / деструкторов по умолчанию.источник
=default
функций), и предоставляемыми пользователем (что имеет место для{}
) функциями. Как объявленные пользователем, так и предоставленные пользователем функции могут предотвращать создание других специальных функций-членов (например, объявленный пользователем деструктор предотвращает генерацию операций перемещения), но только предоставленная пользователем специальная функция делает класс нетривиальным. Правильно?= default
кажется полезным для принуждения компилятора генерировать конструктор по умолчанию, несмотря на присутствие других конструкторов; конструктор по умолчанию не объявляется неявно, если предоставляются любые другие объявленные пользователем конструкторы.Они оба нетривиальны.
Они оба имеют одинаковую спецификацию noexcept в зависимости от спецификации noexcept для баз и членов.
Единственное отличие, которое я обнаружил, состоит в том, что если
Widget
содержит базу или член с недоступным или удаленным деструктором:Тогда
=default
решение будет скомпилировано, ноWidget
не будет разрушаемым типом. Т.е. если вы попытаетесь уничтожить aWidget
, вы получите ошибку во время компиляции. Но если нет, у вас есть рабочая программа.Otoh, если вы предоставите деструктор, предоставленный пользователем , то вещи не будут компилироваться независимо от того, уничтожаете ли вы
Widget
:источник
=default;
компилятор не будет генерировать деструктор, если он не используется, и, следовательно, не будет вызывать ошибку. Это кажется странным для меня, даже если это не обязательно ошибка. Я не могу себе представить, что такое поведение является обязательным в стандарте.Важное различие между
и
является то, что конструктор по умолчанию, определенный с помощью
B() = default;
, считается не определенным пользователем . Это означает, что в случае инициализации значения, как вБудет иметь место специальный тип инициализации, который вообще не использует конструктор, а для встроенных типов это приведет к нулевой инициализации . В случае
B(){}
этого не произойдет. Стандарт C ++ N3337 § 8.5 / 7 говоритНапример:
возможный результат:
http://ideone.com/k8mBrd
источник