Question

I have been coding in C++ for past few years. But there is one question that I have not been able to figure out. I want to ask, are all temporaries in C++, rvalues?

If no, can anyone provide me an example where temporary produced in the code is an lvalue?

Was it helpful?

Solution

No.

The C++ language specification never makes such a straightforward assertion as the one you are asking about. It doesn't say anywhere in the language standard that "all temporary objects are rvalues". Moreover, the question itself is a bit of misnomer, since the property of being an rvalue in the C++ language is not a property of an object, but rather a property of an expression (i.e. a property of its result). This is actually how it is defined in the language specification: for different kinds of expressions it says when the result is an lvalue and when it is an rvalue. Among other things, this actually means that a temporary object can be accessed as an rvalue as well as an lvalue, depending on the specific form of expression that is used to perform the access.

For example, the result of literal 2 + 3 expression is obviously an rvalue, a temporary of type int. We cannot apply the unary & to it since unary & requires an lvalue as its operand

&(2 + 3); // ERROR, lvalue required

However, as we all know, a constant reference can be attached to a temporary object, as in

const int &ri = 2 + 3;

In this case the reference is attached to the temporary, extending the lifetime of the latter. Obviously, once it is done, we have access to that very same temporary as an lvalue ri, since references are always lvalues. For example, we can easily and legally apply the unary & to the reference and obtain a pointer to the temporary

const int *pi = &ri;

with that pointer remaining perfectly valid as long as the temporary persists.

Another obvious example of lvalue access to a temporary object is when we access a temporary object of class type through its this pointer. The result of *this is an lvalue (as is always the case with the result of unary * applied to a data pointer), yet it doesn't change the fact that the actual object might easily be a temporary. For a given class type T, expression T() is an rvalue, as explicitly stated in the language standard, yet the temporary object accessed through *T().get_this() expression (with the obvious implementation of T::get_this()) is an lvalue. Unlike the previous example, this method allows you to immediately obtain a non-const-qualified lvalue, which refers to a temporary object.

So, once again, the very same temporary object might easily be "seen" as an rvalue or as an lvalue depending on what kind of expression (what kind of access path) you use to "look" at that object.

OTHER TIPS

Prasoon Saurav already linked a very good clc++ thread. In there, James Kanze explains why the question doesn't really make sense. It boils down to:

  • rvalue-ness is a (boolean) property of expressions - each expression is either an lvalue or an rvalue
  • temporaries are not expressions

For that reason, the question doesn't make sense.

A good example is the following code:

int main() {
  const int& ri = 4;
  std::cout << ri << std::endl; 
}

The temporary int with value 4 is not an expression. The expression ri that's printed is not a temporary. It's an lvalue, and refers to a temporary.

well, that array operator returns a reference, any function that returns a reference could be considered to do the same thing? all references are const, while they can be lvalues, they modify what they reference, not the reference itself. same is true for the *operator,

*(a temp pointer) = val;

I swear I used to use some compiler that would pass temp values to any function that took a reference,

so you could go:

int Afunc()
{
   return 5;
}

int anotherFunc(int & b)
{
    b = 34;
}


anotherFunc(Afunc());

can't find one that lets you do that now though, the reference has to be const in order to allow passing of temp values.

int anotherFunc(const int & b);

anyway, references can be lvalues and temporary, the trick being the reference it's self is not modified, only what it references.

if you count the-> operator as an operator, then temporary pointers can be lvalues, but the same condition applies, its not the temp pointer that would be changed, but the thing that it points to.

An array indexing operation is both a temporary and an lvalue, something like a[10] = 1 is an example of what you're looking for; the lvalue is a temporary, calculated pointer.

Short answer: yes, but I'm not going to quote the standard, because proving the point would require addressing every kind of temporary there is. By definition a temporary has a lifetime of one statement, so assigning things to one would be poor style at best.

Interesting answer: Copy elision can make (often makes) a temporary object identical with an lvalue object. For example,

MyClass blah = MyClass( 3 ); // temporary likely to be optimized out

or

return MyClass( 3 ); // likely to directly initialize object in caller's frame

Edit: as for the question of whether there is any temporary object in those cases, §12.8/15 mentions

the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copy

which would indicate that there is a temporary object which may be identical with an lvalue.

It depends on what you consider a temporary variable is. You can write something like

#include <stdio.h>
int main()
{
    char carray[10];
    char *c=carray+1;
    *(c+2+4) = 9;
    printf("%d\n",carray[7]);
    return 0;
}

This runs in VisualStudios and GCC. You can run the code in codepad

I consider (c+2+4) a rvalue although i want to assign to it. When i dereference it, it would become an lvalue. So yes all temporaries are rvalues. But you can make rvalues (thus a temporary) into an lvalue by dereferencing it

If no, can anyone provide me an example where temporary produced in the code is an lvalue?

The following code binds a constant reference to a temporary object of type const float created by the compiler:

int i;
const float &cfr = i;

The behaviour is "as if":

int i;
const float __tmp_cfr = i; // introduced by the compiler
const float &cfr = __tmp_cfr;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top