简体   繁体   中英

Why a reference is returned in an assignment operator overload?

I read that, reference is returned from a overloaded assignment operator to enable operator chaining. But without that return also, operator chaining seems to work.

Can someone shed some light on this?

class A
{
    public:
        int x,y;
        char* str;

        //Default Constructor
        A(){}

        //Constructor
        A(int a, int b, char* s){
            cout<<"initialising\n";
            x = a;
            y = b;
            str = new char[10];
            str = s;
        }

        //Destructor
        ~A(){}

        //Overloaded assignment operator
        const A& operator=(const A& obj)
        {
            cout<<"Invoking Assignment Operator\n";
            x = obj.x;
            y = obj.y;
            str = new char[10];
            str = obj.str;

            //return *this;
        }
};

ostream& operator<<(ostream& os, const A& obj)
{
    os <<"X="<< obj.x<<" Y="<<obj.y<<" Str="<<obj.str<<"\n";
    return os;
}

int main()
{
    A c(3,4,"Object C");
    cout<<c;

    A d, e, f;
    d = e = f = c;  //Assignment operator invoked 3 times
    cout<<e;
}

Output:

initialising
X=3 Y=4 Str=Object C
Invoking Assignment Operator
Invoking Assignment Operator
Invoking Assignment Operator
X=3 Y=4 Str=Object C

You're running into undefined behavior because the return type expected from operator = is const A& and you're not returning anything.

It's just unlucky that it works for you. (yes, unlucky, because undefined behavior that appears to work is the worst)

I get a compile error in MSVS, and ideone.com runs into a runtime error.

http://ideone.com/xTDb6

This rule originated from code something like this:

struct Foo { 
    Foo& copy(const Foo& x) { 
        return (*this = x); 
    } 
};

At that time, two things were different about C++:

  1. The compiler-generated operator= returned an rvalue by default, and
  2. The compiler allowed a non-const reference to bind to a temporary.

The code above was intended to be equivalent to:

*this = x;
return *this;

But, it wasn't -- since operator= returned an rvalue, the compiler generated a temporary to hold the result of the assignment, then since the function returned a reference, it returned a reference to that temporary. Then, of course, things went badly in a hurry, because you now had a dangling reference to a temporary that was destroyed at the end of the full expression in which it was created. In short, a class case of returning a reference to a local -- except that it took quite a bit of analysis to realize that the local was being generated at all, not to mention a reference to it being returned.

If you define your operator= to return a value instead of a reference, it's going to have to generate a temporary, just like the compiler did in the code above. I haven't thought through the rest in detail to figure out whether the other changes in the current language would be enough to protect you in a case like this, but my immediate reaction is that you're about halfway to reconstituting that ancient bug, so unless you have absolutely no choice in the matter, I'd stay well away.

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