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

Почему С++ позволяет перемещать классы, содержащие объекты с удаленными операциями перемещения?

Почему мне разрешено использовать std::move для класса, который содержит поля типа с семантикой удаленных перемещений (case 1), но мне не разрешено использовать его в экземпляре такого класса (case 2)?

Я понимаю случай 2. Я явно удалил конструктор перемещения, поэтому я получаю сообщение об ошибке, если попытаюсь его переместить. Но я ожидал бы, что это также будет иметь место в случае 1, где этот класс также перемещается.

class TestNonMovable {
  std::string ss;
 public:
  TestNonMovable(){}
  TestNonMovable(const TestNonMovable&) {}
  TestNonMovable(TestNonMovable&&) = delete;
};

class SomeClass {
  TestNonMovable tnm;
};

int main() {    
    // case1: This compiles, my understanding is that for SomeClass::tnm compiler will use copy constrctor
    SomeClass sc1;
    SomeClass sc2 = std::move(sc1);

    // case2: This does not compile, move constructor is explicitly deleted, compiler will not try using copy constructor
    TestNonMovable tnm;
    TestNonMovable tnm2 = std::move(tnm); //error: use of deleted function 'TestNonMovable::TestNonMovable(TestNonMovable&&)'
}
4b9b3361

Ответ 1

Обратите внимание на разницу между двумя классами. Для TestNonMovable (случай 2) вы явно объявите конструктор перемещения как delete. С помощью TestNonMovable tnm2 = std::move(tnm); конструктор удаленных перемещений выбирается в разрешении перегрузки, а затем вызывает ошибку.

Для SomeClass (случай 1) вы явно не объявляете конструктор перемещения и копирования. Конструктор копирования будет неявно объявлен и определен, но конструктор перемещения будет неявно объявлен и определен как удаленный, поскольку он имеет недвижущийся элемент данных. Обратите внимание, что удаленный неявно объявленный конструктор перемещения не будет участвовать в разрешении перегрузки. С помощью SomeClass sc2 = std::move(sc1); выбирается конструктор копирования, а затем код работает нормально. Ссылка rvalue, возвращаемая из std::move, может быть привязана к lvalue-reference для const (т.е. const SomeClass&).

Удаленный неявно объявленный механизм перемещения игнорируется разрешением перегрузки (в противном случае это предотвратит инициализацию копирования от rvalue). (поскольку С++ 14)

BTW: std:: move сам разрешен в обоих случаях. Он не выполняет операцию перемещения, он просто преобразует аргумент в значение rvalue. Операция перемещения происходит при построении в обоих случаях.