3

I'm puzzling over the following code, which (surprisingly, to me) compiles:

class A {
  int a=0;
};

A returnsA(void)
{
  static A myA;

  return myA;
}

void works(void)
{
  A anotherA;

  returnsA() = anotherA;
}

I can't find anything in the standard or on the web which suggests that it shouldn't compile. It just seems very weird, to me.

I guess returnsA() is returning an object (a copy of myA), so we invoke the default copy assignment operator on it, anotherA gets copy-assigned to the returned object, which then goes out of scope and is destroyed.

I was expecting behavior more like this, which doesn't compile:

int returnsint(void)
{
  static int i=0;

  return i;
}

void doesntwork(void)
{
  int anotherint=0;

  returnsint() = anotherint;
}

Can anybody enlighten me further about this behavior?

Brent Baccala
  • 987
  • 1
  • 6
  • 18

1 Answers1

5

Objects are not lvalues or rvalues. The words lvalue and rvalue are expression categories. They categorize expressions, not objects.


For the line:

returnsA() = anotherA;

since the operands of = are class types, an overloaded operator function is searched for. operator= is special in that if the user does not explicitly overload it, there is a default overload generated. That overload is a member function with signature:

A& A::operator=(A const&);

and the call returnsA() = anotherA; is transformed to returnsA().operator=(anotherA);, this is the basic mechanics of member operator overloading.

The expression returnsA() has category prvalue. However it is perfectly fine to call member functions on prvalue expressions, so there is no problem here.


If you want to dissuade your class from accepting this sort of assignment, see here. And for why the default assignment operator doesn't work that way, see here.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • Did you mean "Objects may be either lvalues or rvalues?" They are either one or the other. You even pointed out the `returnsA()` yields a prvalue. – doug Sep 25 '18 at 05:11
  • 1
    @doug no, I meant what I said. Objects are not expressions, expressions are not objects. Those are different concepts. `returnsA()` *is* a prvalue expression (it does not "yield" a prvalue). Executing this expression *might* cause materialization of a temporary object, but the expression is not the object and vice versa. – M.M Sep 25 '18 at 05:34