Что означает «default» после объявления функции класса?

221

Я видел defaultрядом с объявлениями функций в классе. Что оно делает?

class C {
  C(const C&) = default;
  C(C&&) = default;
  C& operator=(const C&) & = default;
  C& operator=(C&&) & = default;
  virtual ~C() { }
};
Пол Манта
источник
26
Что делает «&», предшествующий «=» в объявлениях оператора присваивания?
dshin

Ответы:

249

Это новая функция C ++ 11 .

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

Вы также можете использовать, = deleteчтобы указать, что вы не хотите, чтобы компилятор генерировал эту функцию автоматически.

С введением конструкторов перемещения и операторов присваивания правила для генерации автоматических версий конструкторов, деструкторов и операторов присваивания стали довольно сложными. Использование = defaultи = deleteделает вещи проще, так как вам не нужно помнить правила: вы просто говорите, что хотите, чтобы произошло.

Петр Александр
источник
17
= deleteсильнее: это означает, что использование этой функции запрещено, хотя она все еще участвует в разрешении перегрузки.
Дедупликатор
2
Но если мы хотим использовать определение, генерируемое компилятором, не должны ли мы пропустить написание этой функции вместо того, чтобы «сначала написать ее, а затем присвоить ей значение по умолчанию»?
Mayank Jindal
47

Это новая функция C ++ 0x, которая указывает компилятору создать версию по умолчанию соответствующего конструктора или оператора присваивания, то есть ту, которая просто выполняет действие копирования или перемещения для каждого члена. Это полезно, потому что конструктор перемещения не всегда генерируется по умолчанию (например, если у вас есть собственный деструктор), в отличие от конструктора копирования (и аналогично для присваивания), но если нет ничего нетривиального для записи, лучше позволить с этим справится компилятор, чем каждый раз разбираться в нем.

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

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

См. Раздел 12.8 стандарта для деталей.

Керрек С.Б.
источник
5
Хотя это не только для конструкторов и заданий, но также относится и к operator new/new[], operator delete/delete[]и их перегрузка.
Себастьян Мах
21

Это новое в C ++ 11, смотрите здесь . Это может быть очень полезно, если вы определили один конструктор, но хотите использовать значения по умолчанию для других. До C ++ 11 вам нужно было бы определить все конструкторы, как только вы их определили, даже если они эквивалентны значениям по умолчанию.

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

juanchopanza
источник
5
Что касается второго абзаца, можете ли вы привести пример?
Джон Смит
11

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

dshin
источник
1

C ++ 17 N4659 стандартная версия

https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 11.4.2 «Явно-дефолтные функции»:

1 Определение функции формы:

attribute-specifier-seq opt decl-specifier-seq opt declarator virt-specifier-seq opt = default ;

называется явно дефолтным определением. Функция, которая явно установлена ​​по умолчанию, должна

  • (1.1) - быть специальной функцией-членом,

  • (1.2) - иметь один и тот же объявленный тип функции (за исключением, возможно, отличающихся ref-квалификаторов и за исключением того, что в случае конструктора копирования или оператора назначения копирования тип параметра может быть «ссылкой на неконстантный T», где T - это имя класса функции-члена), как если бы оно было неявно объявлено, и

  • (1.3) - не имеет аргументов по умолчанию.

2 Явно дефолтная функция, которая не определена как удаленная, может быть объявлена ​​constexpr, только если она была бы неявно объявлена ​​как constexpr. Если функция явно установлена ​​по умолчанию в своем первом объявлении, она неявно считается constexpr, если неявное объявление будет.

3 Если объявленная по умолчанию функция объявлена ​​с указателем noexcept-spec, который не выдает такую ​​же спецификацию исключения, как неявное объявление (18.4), то

  • (3.1) - если функция явно установлена ​​по умолчанию в своем первом объявлении, она определяется как удаленная;

  • (3.2) - в противном случае программа некорректна.

4 [Пример:

struct S {
  constexpr S() = default;            // ill-formed: implicit S() is not constexpr
  S(int a = 0) = default;             // ill-formed: default argument
  void operator=(const S&) = default; // ill-formed: non-matching return type
  ~ S() noexcept(false) = default;    // deleted: exception specification does not match
private:
  int i;                              // OK: private copy constructor
  S(S&);
};
S::S(S&) = default;                   // OK: defines copy constructor

- конец примера]

5 Явно-дефолтные функции и неявно объявленные функции в совокупности называются дефолтными функциями, и реализация должна предоставлять для них неявные определения (15.1, 15.4, 15.8), что может означать определение их как удаленных. Функция предоставляется пользователем, если она объявлена ​​пользователем и не имеет явных значений по умолчанию или удалена в первом объявлении. Предоставленная пользователем явно дефолтная функция (т. Е. Явно дефолтная после ее первого объявления) определяется в точке, где она явно дефолтна; если такая функция неявно определена как удаленная, программа является некорректной. [Примечание: Объявление функции по умолчанию после ее первого объявления может обеспечить эффективное выполнение и краткое определение при одновременном включении стабильного двоичного интерфейса в развивающуюся базу кода. - конец примечания]

6 [Пример:

struct trivial {
  trivial() = default;
  trivial(const trivial&) = default;
  trivial(trivial&&) = default;
  trivial& operator=(const trivial&) = default;
  trivial& operator=(trivial&&) = default;
  ~ trivial() = default;
};
struct nontrivial1 {
  nontrivial1();
};
nontrivial1::nontrivial1() = default;       // not first declaration

- конец примера]

Тогда вопрос, конечно, в том, какие функции могут быть неявно объявлены и когда это происходит, что я объяснил на:

Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
источник