Search code examples
c++constantsmoveautostdmove

Why am I getting a const reference when I for(auto& it : myUnorderedMap) {... = std::move(it.second)}?


Minimally reproducible example 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;
  }
}

gives me

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

I did define a move constructor for Movable and want it to be only moved, never copied, so it's fine that it's not using the regular assignment operator, which I guess it tries to use because it.second returns a const Movable & rather than a Movable &, but why so?

I understand that it.first has to be const, since keys must not be messed with, but it should be fine to move from the values.

Why do I get a const reference here and how can I fix the code so that I can move?


Solution

  • it.second is not const.

    The issue is that user-declaring the move constructor not only deletes the implicitly-declared copy constructor and copy assignment operator, but also inhibits the implicit declaration of the move assignment operator.

    Therefore your class has no move assignment operator and the copy assignment operator is deleted, resulting in the error you are seeing when trying to assign it.second to another Movable.

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

    is an assignment expression, not a variable definition or other initialization of an object that would call a constructor.

    Add

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

    to your class and the move assignment will be possible.