Почему я получаю константную ссылку, когда я для (auto & it: myUnorderedMap) {... = std :: move (it.second)}? - PullRequest
1 голос
/ 30 января 2020

Минимально воспроизводимый пример cpp .sh / 2nlzz :

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>

using namespace std;
int main()
{
  struct Movable {
    Movable() = default;
    Movable ( Movable && ) = default; // move constructor
    vector<int> payload;
  };
  unordered_map<int, Movable> map;
  vector<Movable> target(10);
  int i = 0; 
  for(auto& it : map) {
    target[i] = move(it.second);
    ++i;
  }
}

дает мне

19:15: error: use of deleted function 'main()::Movable& main()::Movable::operator=(const main()::Movable&)'
10:10: note: 'main()::Movable& main()::Movable::operator=(const main()::Movable&)' is implicitly declared as deleted because 'main()::Movable' declares a move constructor or move assignment operator

Я определил конструктор перемещения для Movable и хочу, чтобы он только перемещался, а не копировался, поэтому хорошо, что он не использует обычный оператор присваивания, который, я думаю, он пытается использовать, потому что it.second возвращает const Movable &, а не Movable &, но почему так?

Я понимаю, что it.first должен быть константным, поскольку ключи не должны быть перепутаны, но вполне допустимо переходить от значений.

Почему я получаю ссылку на констант здесь и как я могу исправить код, чтобы я мог двигаться?

Ответы [ 2 ]

3 голосов
/ 30 января 2020

Если вы по умолчанию используете конструктор перемещения, вы также можете захотеть использовать оператор присваивания перемещения по умолчанию самостоятельно. В противном случае он вызовет оператор копирования (который удаляется). В этом случае компилятор не генерирует оператор присваивания перемещения.

Movable& operator=( Movable && ) = default; // move assignment
3 голосов
/ 30 января 2020

it.second - это не const.

. Проблема в том, что объявление пользователя в конструкторе перемещения не только удаляет неявно объявленный конструктор копирования и оператор назначения копирования, но также запрещает неявное объявление Оператор назначения перемещения.

Поэтому в вашем классе нет оператора назначения перемещения, а оператор назначения копирования удален, что приводит к ошибке, которую вы видите при попытке назначить it.second другому Movable.

target[i] = move(it.second);

является выражением присваивания, а не определением переменной или другой инициализацией объекта, который вызовет конструктор.

Добавьте

Movable& operator=(Movable&&) = default;

в ваш класс, и назначение перемещения будет возможно.

...