Каковы правила автоматической генерации операций перемещения?

В 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. Используйте правило нуля, чтобы упростить написание большинства ваших классов.
  2. (Неявно удалено) Явно по умолчанию используется специальная функция-член; если он был бы неявно определен как удаленный, компилятор будет жаловаться.

* замечания, сделанные в комментариях мной (1) и dyp (2)

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

Вот скриншот презентации Говарда Хиннанта "Все, что вы когда-либо хотели знать о семантике перемещения (а затем и некоторых)" с конференции ACCU 2014, которая, на мой взгляд, является очень хорошим напоминанием о правилах автоматического создания специальных членов:

Разъяснение мистера Хиннанта из комментариев:

На слайде этого не сказано, но красные квадраты указывают на устаревшее поведение. Т.е. если вы не хотите зависеть от устаревшего поведения, тогда объявите обоих своих членов-копий, если вы объявите свой деструктор, или одного из членов-копий (в основном следуйте "правилу 3" C++98/03)

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

Другие презентации можно найти здесь: http://accu.org/index.php/articles/1901

Другие вопросы по тегам