1

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?

matthias_buehlmann
  • 4,641
  • 6
  • 34
  • 76
  • You cannot reasonably expect to be able to `move` from a `const` thing. – Jesper Juhl Jan 30 '20 at 17:56
  • 2
    @JesperJuhl, I think OP is asking _why_ it's `const` – ChrisMM Jan 30 '20 at 17:57
  • 4
    Can we get a [mre]? – NathanOliver Jan 30 '20 at 17:58
  • @Jesper Juhl ChrisMM is correct. I understand that I can't move from const. I don't understand why I'm getting const there though. – matthias_buehlmann Jan 30 '20 at 17:59
  • 2
    "*I did define a move constructor for PlaneWithPoints and want it to be only moved, never copied*" - but, did you also implement a move assignment operator as well? The error message would suggest you did not. You are trying to perform a move assignment, but the compiler is choosing to use a copy assignment operator (even though it is deleted), which means there is no move assignment operator available. There is nothing in the code or the error message that suggests this is an issue with `const` at all. – Remy Lebeau Jan 30 '20 at 17:59
  • 1
    If you want something to always be moved and *never* copied, you should declare the copy constructor and copy assignment operators as `= delete`, to make sure copies will never happen. – Jesper Juhl Jan 30 '20 at 18:01
  • @JesperJuhl They are defined as deleted automatically if a user-defined move constructor exists. This is the case here according to the error message. – walnut Jan 30 '20 at 18:04
  • I added a minimal reproducible example – matthias_buehlmann Jan 30 '20 at 18:07
  • 3
    `Movable& operator=(Movable&&) = default;` would help. – Eljay Jan 30 '20 at 18:10
  • @Reny Lebeau, yes I defined a (default) move constructor. Since the thing I access is const, it's clear that I can't move from (so it makes sense that it tries to use the assignment operator instead). But why is it.second const? – matthias_buehlmann Jan 30 '20 at 18:11
  • @user1282931, you need a move assignment, not move constructor. Also, `it.second` isn't actually `const`, you're making an incorrect assumption based on the error. – ChrisMM Jan 30 '20 at 18:12
  • @Eljay that's it! I was under the wrong assumption it would use the move constructor. obviously these are two different things :) – matthias_buehlmann Jan 30 '20 at 18:12
  • @walnut It never hurts to be explicit. – Jesper Juhl Jan 30 '20 at 18:14
  • You need to define move assignment operator `Movable& operator=( Movable && ) = default;` – Maestro Jan 30 '20 at 18:21
  • @user1282931 "*yes I defined a (default) move constructor*' - that is not what I asked. Defining a **move assignment operator** is separate from defining a **move constructor**. – Remy Lebeau Jan 30 '20 at 19:04

2 Answers2

3

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.

walnut
  • 21,629
  • 4
  • 23
  • 59
3

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
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
rranjik
  • 690
  • 9
  • 21