Подтвердить что ты не робот

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

В С++ 98 компилятор С++ может автоматически генерировать конструктор копий и оператор присваивания копиям с помощью членской копии, например

struct X {
    std::string s;
    std::vector<int> v;
    int n;
};

Компилятор автоматически создает экземпляр-конструктор и оператор присваивания копий для X, используя экземпляр-копию.

Но как все меняется в С++ 11 с семантикой перемещения?

Созданы ли сгенерированные автоматически операторы присваивания конструктор и перемещать , например, конструкторы копирования и операторы присваивания копий?

Существуют ли случаи, когда операции перемещения не генерируются автоматически?

4b9b3361

Ответ 1

Из стандартного гл. 12 - Специальные функции-члены

Par 12.8 Копирование и перемещение объектов класса (выделено мной)

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

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

- X не имеет заявленного пользователем оператора копирования,

- X не имеет объявленного пользователем оператора назначения перемещения, и

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

[Примечание: Когда конструктор перемещения не объявляется неявным образом или не предоставляется явно, выражения, которые в противном случае вызвали бы конструктор перемещения, могут вместо этого вызывать конструктор копирования. —Конечная записка]

Затем 11 объясняет правила удаления конструктора перемещения по умолчанию

11 Неявно объявленный конструктор копирования/перемещения является встроенным открытым членом своего класса. По умолчанию конструктор копирования/перемещения для класса X определяется как удаленный (8.4.3), если X имеет:

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

- нестатический член данных типа класса M (или его массив), который нельзя скопировать/переместить, потому что разрешение перегрузки (13.3) применительно к соответствующему конструктору Ms приводит к неоднозначности или функции, которая удаляется или недоступна из дефолтный конструктор,

- прямой или виртуальный базовый класс B, который нельзя скопировать/переместить, поскольку разрешение перегрузки (13.3) применительно к соответствующему конструктору B приводит к неоднозначности или функции, которая удаляется или недоступна из конструктора по умолчанию,

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

- для конструктора копирования - нестатический член данных ссылочного типа rvalue. Конструктор перемещения по умолчанию, который определен как удаленный, игнорируется разрешением перегрузки (13.3, 13.4).

[Примечание: в противном случае удаленный конструктор перемещения мешал бы инициализации из значения r, в котором вместо этого можно использовать конструктор копирования. —Конечная записка]


По сложности всего этого *

Правила могут быть несколько подавляющими. Хорошо бы использовать какую-то технику, чтобы обойти сложность. Примеры:

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

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

Ответ 2

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

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

enter image description here

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

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

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

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