Какой смысл в дефолтных функциях в C ++ 11? - PullRequest
19 голосов
/ 05 мая 2009

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

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

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

Но разве это лучше, чем сейчас?

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

Или мне не хватает варианта использования?

Ответы [ 8 ]

19 голосов
/ 05 мая 2009

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

17 голосов
/ 05 мая 2009

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

функции по умолчанию и удаленные функции - управление настройками по умолчанию

Общая идиома "запрещения" копирование "теперь можно выразить непосредственно:

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
};
12 голосов
/ 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 Final комитета *1019*).

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

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

2 голосов
/ 05 мая 2009

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

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

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

Вот статья, развивающая эту новую функцию.

1 голос
/ 03 ноября 2016

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

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

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

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

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

1 голос
/ 05 мая 2009

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

0 голосов
/ 07 сентября 2011

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

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;
0 голосов
/ 05 мая 2009

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

...