0

I have code like this:

class Pair{
public:
    Pair(Pair && other){};

    Pair(Pair & other){};
};

class IROList{
public:
    virtual const Pair get(const char *key) const = 0;

    inline const Pair operator[](const char *key) const{
        return this->get(key);
        // error: binding ‘const Pair’ to reference of type ‘Pair&&’ discards qualifiers
    }
};

when compiled, it produce

error: binding ‘const Pair’ to reference of type ‘Pair&&’ discards qualifiers

if I change move constructor to const, error dissipated.

    Pair(const Pair && other){};

However, if move constructor takes const, I can not really move the data. I should copy it.

Is there any workaround except removing the const of returning methods, e.g.

    virtual Pair get(const char *key) const = 0;
    inline Pair operator[](const char *key) const;
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Nick
  • 9,962
  • 4
  • 42
  • 80

3 Answers3

6

The problem is you didn't implement your copy constructor well.

instead of :

Pair(const Pair & other){};

you wrote

Pair(Pair & other){};

this causes the constructor to accept only l-value variables, no temporaries, since only const references can bind to temporaries and r-value references.

this forces the compiler to return Pair from get as a r-value-reference (move semantics) since it returns a temporary and it doesn't know how to copy it, only how to move it. again, a temporary can be caught only by const reference or r-value-reference.

r-value-references are not const - this is their all existence! to be caught and their content would be stolen by another object .

to prove my point , here is GCC compiler output with your code (no const):
http://coliru.stacked-crooked.com/a/c390189089434f30 - doesn't compile

and with the const:
http://coliru.stacked-crooked.com/a/0db0fc767e6f10f2 - no compiler errors.

further than that, I whould suggest you to look at std::map implementation or similar classes. there is somewhat agreement between developers on how operator [] should look like and what it returns and why. good software design is far more important then very specific features like move sematincs.

David Haim
  • 25,446
  • 3
  • 44
  • 78
  • did not paid attention for missing const, but never expected this kind of result – Nick Jul 17 '15 at 17:57
  • I hear you, I once spend 30 minutes understanding why didn't my template-code compile, although it had perfect logic inside. it was a missing const. a moment of silent for out precious time – David Haim Jul 17 '15 at 17:59
1

You cannot move a const object as a move operation is a modification. When you move you swap the contents of the old object into the new object. this in turn puts the indeterminate value of the new object into the old object. You could not do that if the old object is const as you would not be able to write to it.

When you use move semantics you want to pass by value. When you pass by value you make a copy that will never be accessed so you are free to move from it. See: Is pass-by-value a reasonable default in C++11?

Community
  • 1
  • 1
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • Thank you for the explanation. I'm fairly new to C++ and I had a hard time finding an explanation as to why a const object can't be moved. There are questions like that whose answers seem obvious to everybody and so as a newbie you can't find answers to them on the internet. – LoneCodeRanger Nov 08 '20 at 12:36
1

Is there any workaround except removing the const of returning methods

No. Returning const values in this case is silly and pointless as the user can simply make a mutable copy at will. You only prohibit optimizations and good semantics (e.g. move semantics) by making it const.

Removing the const isn't a "workaround", it's what should be done irrespective of the issues with move semantics.

Puppy
  • 144,682
  • 38
  • 256
  • 465