Dario
Dario

Reputation: 61

Overloading assignment operator without return statement

Why does the assignment operator is allowed to return void? And why does assignment chaining works in this case? Take a look at the code, it will be very clear what am I talking about.

Code:

struct Foo
{
   std::string str;

   Foo(const std::string& _str)
   : str(_str)
   {
   }

   Foo& operator=(const Foo& _foo)
   {    
      str = _foo.str;
      //return *this; /* NO RETURN! */
   }
};

int main()
{
   Foo f1("1");
   Foo f2("2");
   Foo f3("3");
   f1 = f2 = f3 = Foo("4");

   std::cout << "f1: " << f1.str << std::endl;
   std::cout << "f2: " << f2.str << std::endl;
   std::cout << "f3: " << f3.str << std::endl;

   return 0;
}

Questions:

  1. Why is this legal? (why does it compile at all)
  2. Why does it work?

I've read in many places "assignment operator should return *this so that you can have assignment chaining" which totally makes sense, but then why does the above work?

Try it out:
online c++ workspace with the code from above

Upvotes: 5

Views: 2121

Answers (4)

paper.plane
paper.plane

Reputation: 1197

It's illegal and if it compiles, then in some way it is storing something weird for the runtime. And you must return *this from the function. The correct function definition will look like:

Foo& operator=(const Foo& _foo)
{    
  if(this == &_foo) /* check for self-assignment */
     return *this;

  str = _foo.str;

  return *this;
}

Returning *this is a must for chain assignments like:

Foo  x, y, z;
x = y = z;     /* *this is necessary for this statement */    

Upvotes: 0

Filip
Filip

Reputation: 11

Check what asm code is produced after compiling. My guess is that this function returns what happens to be in register AX (this is c-call standard function implementation if I'm not mistaken). In your case, it happens to be what you are wanting it to be... if you add some functionality to function you might break it...

Upvotes: 0

Andy Prowl
Andy Prowl

Reputation: 126432

Why is this legal? (why does it compile at all)

This is not legal, and injects Undefined Behavior in your program. Your compiler should at least warn you about that (and I believe it does, if you set a sufficiently high warning level).

Per Paragraph 6.6.3/2 of the C++11 Standard:

Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.

The only exception is the main() function, which is allowed to have a missing return statement. Per Paragraph 3.6.1/5:

A return statement in main has the effect of leaving the main function (destroying any objects with automatic storage duration) and calling std::exit with the return value as the argument. If control reaches the end of main without encountering a return statement, the effect is that of executing

return 0;

Finally:

Why does it work?

Undefined Behavior means that your program may run on some machines but not on others; or it may run on all machines today, but not tomorrow; or it will cause your program to have some bizarre, unpredictable outcome; including (which is the worst case) seeming to run perfectly fine.

Upvotes: 8

juanchopanza
juanchopanza

Reputation: 227420

What you have is undefined behaviour, because you are flowing off the end of a function that promises to return something.

The only function for which it is legal to do this in C++ is int main() (and version with arguments), because it implicitly returns 0 in the absence of a return statement.

Upvotes: 2

Related Questions