В чем смысл дефолтных функций в C ++ 11?

C ++ 11 добавляет способность сообщать компилятору о создании реализации по умолчанию любой из специальных функций-членов . Хотя я вижу значение удаления функции, где значение явно дефолт функции? Просто оставьте поле пустым, и компилятор все равно сделает это.

Единственное, что я вижу, это то, что конструктор по умолчанию создается только тогда, когда не существует другого конструктора:

class eg { public: eg(int i); eg() = default; }; 

Но разве это действительно лучше, чем вы это делаете сейчас?

 class eg { public: eg(int i); eg() {} }; 

Или я пропустил прецедент?

По умолчанию конструктор будет иметь объявление, и это объявление будет подчиняться нормальным правилам доступа. Например, вы можете защитить конструктор копии по умолчанию. Без этих новых объявлений создаваемые по умолчанию члены являются общедоступными.

Эти примеры с веб-сайта Stroustrup могут помочь вам понять суть:

дефолтные и удаленные функции – контроль значений по умолчанию

Теперь можно прямо выражать общую идиоту «запрещения копирования»:

 class X { // ... X& operator=(const X&) = delete; // Disallow copying X(const X&) = delete; }; 

Напротив, мы также можем явно сказать, что мы хотим использовать поведение по умолчанию:

 class Y { // ... Y& operator=(const Y&) = default; // default copy semantics Y(const Y&) = default; }; 

Явное указание на значение по умолчанию явно избыточно, но комментарии к этому эффекту и (что еще хуже) пользователь, явно определяющий операции копирования, предназначенные для предоставления поведения по умолчанию, не редкость. Оставить его компилятору для реализации поведения по умолчанию проще, меньше подвержено ошибкам и часто приводит к улучшению объектного кода. Механизм «по умолчанию» может использоваться для любой функции, которая имеет значение по умолчанию. Механизм «delete» может использоваться для любой функции. Например, мы можем исключить нежелательное преобразование следующим образом:

 struct Z { // ... Z(long long); // can initialize with an long long Z(long) = delete; // but not anything less }; 

Помимо изменения доступности (частных / защищенных) сгенерированных функций, вы сможете сделать их виртуальными.

 struct S { virtual ~S(); virtual S& operator=(const S&); }; S::~S() = default; S& S::operator=(const S&) = default; 

Могут быть изменены следующие аспекты дефолтных функций:

  • доступ (быть непубличным)
  • виртуальный
  • явные (конструкторы)
  • спецификации исключения
  • константа параметров

но для этого функции должны быть определены вне classа (8.4.2 / 2 в проекте окончательного комитета C ++ 0x ).

Версия оригинального предложения Лоуренса Кроула здесь .

Спасибо Роджеру Пате за разъяснение и цитату.

1) Неявно сгенерированные деструкторы в настоящее время не являются виртуальными. Поэтому вам нужно определить их, чтобы сделать их виртуальными, и в этом случае они не так эффективны. With = default, у вас будут как виртуальные, так и эффективные, как неявно созданные деструкторы.

2) У них будут спецификаторы доступа, в отличие от неявно сгенерированных.

3) Если вы встраиваете свой конструктор по умолчанию, ваш class по-прежнему остается тривиальным.

Вот статья, посвященная этой новой функции.

Я подозреваю, что возможность создания по умолчанию конструктора копирования будет действительно полезна. Я не вижу использования для дефолта, генерирующего конструктор по умолчанию, поскольку, как вы говорите, реализация, которую вы вводите, будет короче.

См. Пункт 17 из большой книги Скотта Майера « Эффективный современный C ++ ». В нем описываются многие условия, при которых создаются конструкторы копирования по умолчанию, операции копирования и операции перемещения (или НЕ сгенерированы).

Другими словами, компилятор не может «делать это в любом случае». Но если специальная функция-член по умолчанию имеет смысл, пользователь может использовать ключевое слово «по умолчанию», чтобы явным образом сказать компилятору сгенерировать функцию по умолчанию, которая иначе не будет сгенерирована.

Из вещей, которые нужно помнить в конце пункта 17:

  • Операции перемещения генерируются только для classов, не имеющих явно объявленных операций перемещения, операций копирования или деструктора.

  • Конструктор копирования создается только для classов, не имеющих явно объявленного конструктора копирования, и он удаляется, если объявлена ​​операция перемещения. Оператор присваивания копий генерируется только для classов, не имеющих явно объявленного оператора назначения копирования, и он удаляется, если объявлена ​​операция перемещения. Генерация операций копирования в classах с явно объявленным деструктором устарела.

Для меня это функция отключения, которая будет полезна. Для большинства classов, которые я в настоящее время создаю, я отключил копирование и назначение – было бы неплохо иметь функцию, которую компилятор может распознать для этого, а не в зависимости от ошибок компоновщика.

Defaulting более полезен для copy-constructors, если у вас есть class с большим количеством атрибутов. Например, если у вас есть этот class:

 class MyClass { private: int offset; std::string name; std::vector relatives; float weight; MyClass* spouse; Vehicle* car; double houseArea; Date birth; Person* parents[2]; public: /* Default constructor will be defined here */ }; 

вместо того, чтобы определять конструктор-копию следующим образом:

 MyClass(const MyClass& that) : offset(that.offset), name(that.name), relatives(that.relatives), weight(that.weight), spouse(that.spouse), car(that.car), houseArea(that.houseArea), birth(that.birth), parents(that.parents) {} 

вы бы определили этот способ:

 MyClass(const MyClass&) = default; 
Давайте будем гением компьютера.