简体   繁体   中英

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?

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.

If you default the move constructor, you may want to default the move assignment operator yourself, too. Otherwise it would call into the copy assignment operator (which is deleted). A move assignment operator is not generated by the compiler for you in this case.

Movable& operator=( Movable && ) = default; // move assignment

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM