Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are temporary C++ objects lvalues? [duplicate]

Tags:

c++

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?

like image 772
Brent Baccala Avatar asked Dec 21 '25 03:12

Brent Baccala


1 Answers

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.

like image 82
M.M Avatar answered Dec 23 '25 15:12

M.M