c++pointersmove-semanticsrvalue

move assignment argument throws error when dereferenced but works when member accessed directly


In the minimum needed code snippet, in the move assignment, why is the commented line *arg = nullptr; illegal and arg.p = nullptr; okay? If I understand correctly, both are modifying rvalue, yet on compilation *arg = nullptr; produces error saying:

left operand must be l-value

I would expect *arg to provide access to arg's p because of operator overloading.

#include <iostream>

using namespace std;

class Ptr {
public:
    Ptr(double arg) :p{ new double(arg) } {}
    // copy constructor
    Ptr(const Ptr& arg) {
        p = new double(*(*arg));
    }
    // move assignment
    Ptr& operator=(Ptr&& arg) {
        delete p;
        p = *arg;
        cout << "move type of *arg " << typeid(*arg).name() << endl;
        arg.p = nullptr;
        //*arg = nullptr; // illegal
        return *this;
    }
    double* operator*() {
        return p;
    }
    const double* operator*() const {
        return p;
    }
    ~Ptr() {
        delete p;
    }
private:
    double* p;
};

Ptr copy(Ptr a) { return a; }


int main() {
    Ptr pt{ 2 };
    Ptr pt2{ 3 };
    pt2 = copy(pt);
    return 0;
}

Tried chatGpt for help, however, it thinks I am trying to assign a pointer to a double which is clearly not the case because if I do cout << "type of *arg " << typeid(*arg).name()<<endl; a pointer type is seen.

EDIT: Removed misleading comment for operator*. I would like to keep the code as is. Problem is partly from PPP3, Chapter 17, drill by Bjarne Stroustrup. I am interested in the WHY.


Solution

  • I would expect *arg to provide access to arg's p because of operator overloading.

    The problem is that your overloaded operator*'s return by value which means a call to those functions as in *arg is an rvalue expression.

    To solve this, you can return the pointer by lvalue reference as shown below.

    //---------v------------------>return by reference
        double*& operator*() {
            return p;
        }
    

    Working Demo