Имейте в виду, что означает «перемещать» данные в C ++ (при условии, что мы следуем обычным соглашениям). Если вы переместите объект x
в объект y
, то y
получит все данные, которые были в x
, а x
- это ... ну, нам все равно, что такое x
, пока это все еще действует для уничтожения. Часто мы думаем о x
как о потере всех своих данных, но это не обязательно. Все, что требуется, это то, что x
является действительным. Если x
заканчивается теми же данными, что и y
, нам все равно.
Копирование x
в y
заставляет y
получать все данные, которые были в x
и x
остается в допустимом состоянии (при условии, что операция копирования выполняется в соответствии с соглашениями и не содержит ошибок). Таким образом, копирование считается движением. Причина определения операций перемещения в дополнение к операциям копирования заключается не в том, чтобы разрешить что-то новое, а в некоторых случаях для повышения эффективности. Все, что может быть скопировано, может быть перемещено, если вы не предпримете шаги для предотвращения перемещений.
Так что я вижу, что A
является неподвижным классом из-за определения его операций управления копированием, поэтому он может быть скопировано только и любая попытка переместить объект этого класса, вместо этого используется соответствующая операция копирования.
Я вижу, что A
является подвижным классом (несмотря на отсутствие конструктора перемещения и назначения перемещения) из-за определения его операций управления копированием. Любая попытка переместить объект этого класса приведет к соответствующей операции копирования. Если вы хотите, чтобы класс был копируемым, но не перемещаемым, вам нужно удалить операции перемещения, сохранив при этом копии. (Попробуйте. Добавьте A(A&&) = delete;
к определению A
.)
Класс B
имеет одного члена, который можно перемещать или копировать, и одного члена, который может быть перемещено, но не скопировано. Таким образом, B
может быть перемещен, но не скопирован. При перемещении B
элемент unique_ptr
будет перемещен, как вы ожидаете, и элемент A
будет скопирован (запасной вариант для движущихся объектов типа A
).
Ситуация для меня становится еще хуже: если я раскомментирую строки операций перемещения в B
, приведенная выше инициализация не скомпилирует жалобу на ссылку на удаленную функцию, то же самое для назначения!
Внимательно прочитайте сообщение об ошибке. Когда я реплицировал этот результат, за ошибкой «использование удаленной функции» последовала заметка с более подробной информацией: конструктор перемещения был удален, поскольку «его спецификация исключений не соответствует неявной спецификации исключений». Удаление ключевых слов noexcept
позволило скомпилировать код (используя g cc 9.2 и 6.1).
Кроме того, вы можете добавить noexcept
в конструктор копирования и назначить копирование A
(сохраняя noexcept
на ходу операции B
). Это один из способов продемонстрировать, что операции перемещения по умолчанию B
используют операции копирования A
.