Какой смысл в функциях по умолчанию в С++ 11?

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

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

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

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

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

Или я пропустил вариант использования?


person Motti    schedule 05.05.2009    source источник


Ответы (8)


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

person MSalters    schedule 05.05.2009
comment
[копать] Кроме того: определение некоторых специальных функций-членов не позволяет компилятору устанавливать другие по умолчанию, но это можно снова включить с помощью = default. Например, если вы реализуете собственный конструктор копирования, конструктор перемещения по умолчанию не будет создан. Вместо того, чтобы реализовывать его самостоятельно, вы можете явно указать его по умолчанию, если этого будет достаточно. - person boycy; 31.10.2012

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

функции по умолчанию и удаленные – управление значениями по умолчанию

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

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;

};

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

struct Z {
  // ...

  Z(long long);     // can initialize with an long long
  Z(long) = delete; // but not anything less
};
person Klaim    schedule 05.05.2009
comment
На самом деле я задал этот вопрос после прочтения часто задаваемых вопросов BS по C++0x, его явно избыточный комментарий побудил меня подвергнуть сомнению всю проблему по умолчанию. - person Motti; 05.05.2009
comment
Хм, облом, вы можете использовать =delete для чего угодно, но не =default. Хотелось бы написать int main() = default; // Вернуться к чтению StackOverflow - person MSalters; 05.05.2009

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

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

S::~S() = default;
S& S::operator=(const S&) = default;

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

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

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

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

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

person James Hopkin    schedule 05.05.2009
comment
Почему gcc 4.5.0 выдает следующую ошибку для кода, который вы разместили: «виртуальный S::~S()», объявленный виртуальным, не может быть установлен по умолчанию в теле класса - person bpw1621; 06.08.2010
comment
@bpw: Потому что 8.4.2/2 (проверено в N3092) явно запрещает этот код. - person ; 27.09.2010
comment
@Roger Спасибо за разъяснение (в другом месте). Как вы указали, требуется, я определил функции вне класса. - person James Hopkin; 28.09.2010
comment
Есть ли некоторая двусмысленность, вызванная ее определением в теле класса? Кажется странным, что вы можете сказать virtual ~Class() {} в теле Class, но не virtual ~Class() = default; Есть ли разница в поведении этих двух фрагментов кода в любой ситуации? - person David Stone; 24.03.2012
comment
@David Только то, что это будет неявно встроено, я полагаю - person James Hopkin; 06.04.2012
comment
Это ограничение больше не накладывается на более новые черновики (для меня это N3376 и последовательные черновики C++14). Таким образом, вы можете объявить virtual ~Class() = default. - person Rapptz; 28.08.2013

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

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

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

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

person Özgür    schedule 05.05.2009

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

person 1800 INFORMATION    schedule 05.05.2009

См. пункт 17 из замечательной книги Скотта Мейера Effective Modern C++. Он описывает множество условий, при которых генерируются (или НЕ генерируются) конструкторы копирования по умолчанию, операции копирования и операции перемещения.

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

Из того, что нужно помнить в конце пункта 17:

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

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

person jfritz42    schedule 03.11.2016

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

person Community    schedule 05.05.2009
comment
Даже сейчас (C++98), производным от класса non_copyable, вы можете заставить компилятор обнаруживать ошибки (даже при использовании в самом классе) и не ждать времени компоновки. - person Motti; 05.05.2009
comment
Я не верю в введение деривации для решения таких задач. - person ; 05.05.2009

Использование по умолчанию более полезно для конструкторов копирования, если у вас есть класс с большим количеством атрибутов. Например, если у вас есть этот класс:

class MyClass {
private:
   int offset;
   std::string name;
   std::vector<Person*> 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;
person erdavila    schedule 07.09.2011
comment
Да, но конструкторы копирования по умолчанию создаются компилятором автоматически - person Motti; 07.09.2011