Каковы правила автоматической генерации операций перемещения?
В C++98 компилятор C++ может автоматически генерировать конструктор копирования и оператор присваивания копии через пошаговое копирование, например
struct X {
std::string s;
std::vector<int> v;
int n;
};
Компилятор автоматически генерирует конструктор копирования и оператор присваивания для X
, используя членскую копию.
Но как все меняется в C++11 с семантикой перемещения?
Создаются ли автоматическиконструктор перемещения иоператор присваивания перемещения, например, конструкторы копирования и операторы назначения копирования?
Есть ли случаи, когда операции перемещения не генерируются автоматически?
2 ответа
Из стандартного гл. 12 - Специальные функции-члены
Часть 12.8 Копирование и перемещение объектов класса (выделено мной)
9 Если определение класса X явно не объявляет конструктор перемещения, он будет неявно объявлен как дефолтный, если и только если
- X не имеет объявленного пользователем конструктора копирования,
- X не имеет заявленного пользователем оператора копирования,
- X не имеет объявленного пользователем оператора назначения перемещения, и
- X не имеет объявленного пользователем деструктора.
[Примечание: Когда конструктор перемещения не объявляется неявным образом или не предоставляется явно, выражения, которые в противном случае вызвали бы конструктор перемещения, могут вместо этого вызывать конструктор копирования. —Конечная записка]
затем 11
объясняет правила удаления конструктора перемещения по умолчанию
11 Неявно объявленный конструктор копирования / перемещения является встроенным открытым членом своего класса. По умолчанию конструктор копирования / перемещения для класса X определяется как удаленный (8.4.3), если X имеет:
- вариантный член с нетривиальным соответствующим конструктором и X является объединяющим классом,
- нестатический член данных типа класса M (или его массив), который не может быть скопирован / перемещен, потому что разрешение перегрузки (13.3) применительно к соответствующему конструктору M приводит к неоднозначности или функции, которая удаляется или недоступна из дефолтный конструктор,
- прямой или виртуальный базовый класс B, который нельзя скопировать / переместить, поскольку разрешение перегрузки (13.3) применительно к соответствующему конструктору B приводит к неоднозначности или функции, которая удаляется или недоступна из конструктора по умолчанию,
- любой прямой или виртуальный базовый класс или нестатический член данных типа с деструктором, который удален или недоступен из конструктора по умолчанию, или,
- для конструктора копирования - нестатический член данных ссылочного типа rvalue. Конструктор перемещения по умолчанию, который определен как удаленный, игнорируется разрешением перегрузки (13.3, 13.4).
[Примечание: в противном случае удаленный конструктор перемещения мешал бы инициализации из значения r, в котором вместо этого можно использовать конструктор копирования. —Конечная записка]
По сложности всего этого *
Правила могут быть несколько подавляющими. Хорошо использовать какую-то технику, чтобы обойти сложность. Примеры:
- Используйте правило нуля, чтобы упростить написание большинства ваших классов.
- (Неявно удалено) Явно по умолчанию используется специальная функция-член; если он был бы неявно определен как удаленный, компилятор будет жаловаться.
* замечания, сделанные в комментариях мной (1) и dyp (2)
Никос Атанасиу дал хороший ответ, но я хотел добавить этот инструмент, который я считаю очень полезным.
Вот скриншот презентации Говарда Хиннанта "Все, что вы когда-либо хотели знать о семантике перемещения (а затем и некоторых)" с конференции ACCU 2014, которая, на мой взгляд, является очень хорошим напоминанием о правилах автоматического создания специальных членов:
Разъяснение мистера Хиннанта из комментариев:
На слайде этого не сказано, но красные квадраты указывают на устаревшее поведение. Т.е. если вы не хотите зависеть от устаревшего поведения, тогда объявите обоих своих членов-копий, если вы объявите свой деструктор, или одного из членов-копий (в основном следуйте "правилу 3" C++98/03)
Я рекомендую прочитать слайды, чтобы получить прогрессивную конструкцию этой таблицы и получить подробное объяснение того, как и почему мы имеем это сейчас.
Другие презентации можно найти здесь: http://accu.org/index.php/articles/1901