Условия для автоматического создания оператора по умолчанию / копирования / перемещения и оператора присваивания копирования / перемещения?

127

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

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

oompahloompah
источник

Ответы:

136

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

  • Конструктор по умолчанию создается автоматически, если конструктор, объявленный пользователем, отсутствует (§12.1 / 5).
  • Конструктор копирования генерируется автоматически, если нет объявленного пользователем конструктора перемещения или оператора присваивания перемещения (поскольку в C ++ 03 нет конструкторов перемещения или операторов присваивания перемещения, это упрощается до «всегда» в C ++ 03) ( §12.8 / 8).
  • Оператор присваивания копий генерируется автоматически, если нет объявленного пользователем конструктора перемещения или оператора присваивания перемещения (§12.8 / 19).
  • Деструктор создается автоматически, если деструктор, объявленный пользователем, отсутствует (§12.4 / 4).

Только C ++ 11 и новее:

  • Конструктор перемещения создается автоматически, если нет объявленного пользователем конструктора копирования, оператора присваивания копии или деструктора, и если сгенерированный конструктор перемещения действителен (§12.8 / 10).
  • Оператор присваивания перемещения генерируется автоматически, если нет объявленного пользователем конструктора копирования, оператора присваивания копии или деструктора, и если сгенерированный оператор присваивания перемещения действителен (например, если ему не нужно назначать постоянные члены) (§12.8 / 21).
Philipp
источник
9
Считается ли унаследованный деструктор? Я имею в виду, скажем, у меня есть базовый класс с пустым виртуальным деструктором. Предотвращает ли это создание конструкторов перемещения в подклассах? Если да, поможет ли, если я определю конструктор перемещения в базовом классе?
kamilk 06
10
Я думаю, вам следует упомянуть, возможно, наличие constчленов в классе предотвратит автоматическую генерацию конструктора ...
бессонница
Имеет ли «Бывают ситуации, когда специальные функции-члены объявлены, но определены как удаленные». ссылаетесь на то, где у вас, например, есть константные или ссылочные члены, где перемещение будет невозможно? Нет, этого не может быть, потому что копия будет применена.
Towi
Я знаю, что на этом форуме запрещено отправлять гиперссылки. Но это еще и хорошая статья - cplusplus.com/articles/y8hv0pDG
bruziuz
Обратите внимание, что по стандарту неявно заданный по умолчанию конструктор копирования « устарел, если класс имеет объявленный пользователем оператор присваивания копии или объявленный пользователем деструктор » ( 12.8 Копирование и перемещение объектов класса [class.copy] ).
sigy
98

Я нашел диаграмму ниже очень полезной.

Правила C ++ для автоматических конструкторов и операторов присваивания from Sticky Bits - Стать правилом нулевого героя

Марко М.
источник
Прекрасный. Что означает «независимый»? Независимо от чего?
Towi
8
Копирование / назначение «независимы» друг от друга. Если вы напишете только один, компилятор предоставит другой. Напротив, если вы предоставите либо ctor перемещения, либо назначение перемещения, компилятор не предоставит другой.
Марко М.
Интересно, в чем причина того, что операции копирования независимы. Может быть исторические причины? или тот факт, что копия не изменяет цель, а перемещает?
RaGa__M 05
@Explorer_N Да, обратная совместимость, так что исторические причины. Давным-давно это был плохой выбор дизайна, поэтому теперь существует потребность в хороших практиках, таких как «правило трех» (определить все 3 или ничего: конструктор копирования, оператор присваивания копии и часто деструктор), чтобы избежать трудных для поиска ошибок.
atablash
@MarcoM., Насколько я понял, условие «Если вы напишете ...» включает в себя два случая установки специальной функции-члена на = delete(очевидный) или = default(менее очевидный для меня). Я прав?
Энрико Мария Де Анджелис
2

Стандартный проект C ++ 17 N4659

Для быстрой перекрестной ссылки на стандарты взгляните на разделы «Неявно объявленные» следующих записей cppreference:

Та же информация, конечно, может быть получена из стандарта. Например, на стандартном проекте C ++ 17 N4659 :

15.8.1 «Конструкторы копирования / перемещения» для конструктора копирования:

6 Если определение класса явно не объявляет конструктор копирования, неявный конструктор объявляется неявно. Если в определении класса объявляется конструктор перемещения или оператор присваивания перемещения, неявно объявленный конструктор копирования определяется как удаленный; в противном случае он определяется как значение по умолчанию (11.4). Последний случай считается устаревшим, если класс имеет объявленный пользователем оператор присваивания копии или объявленный пользователем деструктор.

и для конструктора перемещения:

8 Если определение класса X явно не объявляет конструктор перемещения, неявный конструктор будет неявно объявлен как заданный по умолчанию тогда и только тогда, когда

  • (8.1) - X не имеет объявленного пользователем конструктора копирования,

  • (8.2) - X не имеет объявленного пользователем оператора присваивания копии,

  • (8.3) - X не имеет объявленного пользователем оператора присваивания перемещения, и

  • (8.4) - X не имеет деструктора, объявленного пользователем.

15.8.2 «Оператор присваивания копирования / перемещения» говорит о назначении копии:

2 Если определение класса не объявляет явно оператор присваивания копии, он объявляется неявно. Если в определении класса объявляется конструктор перемещения или оператор присваивания перемещения, неявно объявленный оператор присваивания копии определяется как удаленный; в противном случае он определяется как значение по умолчанию (11.4). Последний случай считается устаревшим, если в классе есть объявленный пользователем конструктор копии или объявленный пользователем деструктор.

и для переезда:

4 Если определение класса X не объявляет явно оператор присваивания перемещения, он будет неявно объявлен как принятый по умолчанию тогда и только тогда, когда

  • (4.1) - X не имеет объявленного пользователем конструктора копирования,
  • (4.2) - X не имеет объявленного пользователем конструктора перемещения,
  • (4.3) - X не имеет объявленного пользователем оператора присваивания копии, и
  • (4.4) - X не имеет деструктора, объявленного пользователем.

15.4 «Деструкторы» говорят о деструкторах:

4 Если в классе нет деструктора, объявленного пользователем, деструктор неявно объявляется по умолчанию (11.4). Неявно объявленный деструктор является встроенным публичным членом своего класса.

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