0

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
asked Apr 30, 2012 at 7:50
7
  • 3
    Your code doesn't even compile, how can it work? Commented Apr 30, 2012 at 7:53
  • You are returning by reference, are you aware of that? Commented Apr 30, 2012 at 7:53
  • @Luchian-Its compiling and running fine for me Commented Apr 30, 2012 at 7:56
  • @cppcoder you have an over-permissive compiler. It's undefined behavior. Commented Apr 30, 2012 at 7:56
  • An answer to this question can be found below. In short, eax. stackoverflow.com/questions/1610030/… Commented Apr 30, 2012 at 7:57

2 Answers 2

3

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

answered Apr 30, 2012 at 7:54
Sign up to request clarification or add additional context in comments.

5 Comments

It's strange that it doesn't compile on MSVS. Not having a return statement in a function in declared as returning non-void is legal (syntactically and semantically valid). It's only the run time action of the flow of execution reaching the closing } of the function that causes UB.
If new char[10] throws there is a legal execution path that avoids UB. IMHO MSVS is in error not to compile this.
@Luchian The ideone link you have provided also shows runtime error, not compilation error
@cppcoder that's what I said. MSVS doesn't compile, ideone runs into runtime error.
@LuchianGrigore Re "MS got it right": technically, no. The standard says that it is only undefined behavior if the function is actually called and returns. In practice, I'd prefer the error regardless of whether the function is called or not, but I've had problems in cases where the function could never return: if it's immediately obvious (e.g. a throw outside of any condition), then Microsoft doesn't complain, but if the body is something like fatalError(), Microsoft will refuse to compile the code, even though no undefined behavior is present or can occur.
2

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.

answered Apr 30, 2012 at 8:20

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.