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?
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.
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;
Related
I'm looking at a code snippet which compiles fine;
int a = 10;
int&& b = static_cast<int&&>(a);
The way I'm seeing it, a thing of type T&& is a reference to a temporary -- the underlying object isn't placed in memory.
But a exists in memory. Ergo, how can you have a r-value reference to it?
You're mixing up rvalues and temporaries. Temporaries are objects, rvalues are expressions.
The system of dividing expressions up into the categories lvalue, xvalue, prvalue is designed to help avoid logic errors in the program (for example, preventing 3 = 4; ) but it doesn't have any deeper meaning.
Any object (temporary or not) can be designated by an lvalue expression or an rvalue expression if we really want to . In the case in the question we make an xvalue expression that designates a.
Then we initialize a reference, which binds directly since the type is the same (note: the type , int, not the category).
The code has exactly the same effect as int& b = a; with one single exception, the result of decltype(b).
The comment makes a good point as well -- temporary objects still exist in memory (in the abstract machine) , they are just a different storage class to other objects. And in the case of lifetime-extended temporaries they behave very much like objects of automatic storage.
Going the other way, you can have an lvalue expression designating a temporary object, int const& x = 5; results in the lvalue expression x designating a temporary that has had its lifetime extended.
Or even without lifetime extension, std::string{} = "x" is an lvalue since operator= returns lvalue reference. You could write auto z = (std::string{} = "x") = "y"; which is not a good code style of course but understanding it helps to understand the type and value category system .
It's illegal to:
constexpr int& v = 1; since vcannot be resolved at compile-time, which makes sense.
Now it surprised me that const int& v = 1; is legal.
However I cannot see how this is different from const int v = 1;.
In what case would it be necessary to bind a const lvalue reference to an rvalue?
constexpr int& v and const int& v are not the same thing. constexpr int& v means create a reference to an int and that reference is a constexpr. You can't bind that to a temporary because lvalue references to mutable object are not allowed to bind to a temporary.
const int& v on the other hand means create a reference to a const int. This is allowed to bind to a temporary since you cannot modify the state of the temporary.
In what case would it be necessary to bind a const lvalue reference to an rvalue?
Pre C++11, this was the only way to capture a reference to a temporary. For example
std::vector<int> make_vec(int size) { return std::vector<int>(size); }
const std::vector<int>& foo = make_vec(1000);
In the above code, ignoring any sort of optimization, this is the only way to access the vector that make_vec returns without making a copy of it. This was/is very important as it helps to prevent a lot of copies that C++'s value semantics naturally creates.
Post C++11 it's not needed as much as we now have rvalue references that allow you to bind a reference to a temporary, and you can modify it since they are typically not const.
Languages like C++ are designed in terms of what they can do, more than they are designed in terms of what they can't. So your question shouldn't be "in what case is this necessary" [never], but "what features of the language make this possible?" In this case, the main feature is what is known as "the most important const", whereby a const reference can be bound to an rvalue, extending its lifetime until the end of the reference's scope. This is sometimes useful for rvalues that are returned from function calls or other expressions. But integer literals are also rvalues. It was more practical to specify the behavior of binding a const reference to any rvalue, than to come up with more stringent rules about what kind of rvalues were worthy of such a treatment.
For what reason would it be necessary to bind a const lvalue reference to an rvalue?
While not necessary per se, this is very useful when calling functions with lvalue reference arguments:
class foo;
void bar(const foo&);
bar({}); // lvalue reference bound to rvalue
I'll take a guess at the answer: It won't seem that either the membership access operator (.) or the membership dereference operator (->) is defined for this statement const int& v = 1;, so the statement just has to have that effect, even though it shouldn't really be able to have that outcome.
On the other hand, if you were to say, const std::string& s = 1;, this should not work unless operator= is overloaded to make it have the effect you would want.
A problem with *this can be caught at compile time, but a problem with a bad integer value or pointer value usually isn't.
Why it is not possible to convert rvalues to lvalues? It is possible to do a conversion in the opposite direction though. Technically rvalues do have a memory address, isn't it?
You can:
int&& x = 3;
x is now an lvalue. A so called 'rvalue-reference' can bind to a temporary,
but anything with a name is an lvalue, so you need to forward<>() it if you need it's rvalueness back.
Note that by binding a temporary to a rvalue-reference (or a const reference) you extend its lifetime. Technically a cast is possible,
but not recommended, since temporaries have short lifetime, so you
typically get a dangling reference.
It is rather straightforward to write a template function unmove(), that does the opposite of std::move():
template<class T> T& unmove(T&& t) { return t; }
Please note that, according to the standard since C++11:
a temporary bound to a reference parameter in a function call exists until the end of the full expression containing that function call: if the function returns a reference, which outlives the full expression, it becomes a dangling reference.
So it is safe to use unmove() within a single full expression, but after the expression has been fully evaluated, the temporaries go away.
My common use for unmove() is to call functions / methods, that return values through references, when I don't need those values.
Correct an anwer above.
int&& x = 3;
x is 'rvalue-reference'. See
https://www.tutorialspoint.com/What-is-double-address-operator-and-and-in-Cplusplus
class A {}
A foo() {
A a;
// some work
return a;
}
Here it returns an instance of A, and I saw many readings saying that this returns a rvalue.
My confusion is, since it's perfectly legit to do A b; a = b;, the variable a seems to be an lvalue. So why does it become rvalue when it's the returned one?
There is no such thing as an rvalue object.
Rvalue and lvalue refers to expressions.
One expression that refers to an object can be an rvalue, while another that refers to the same object can be an lvalue.
Originally "lvalue" referred to any expression that could be on the left hand side of C's =, while "rvalue" was any expression that could only be on the right side. Since then C++ has acquired const and references, and things have got complicated. But the early C view of things is useful to understand this.
Regarding …
” the variable a seems to be an lvalue. So why does it become rvalue when it's the returned one?
Well, the variable in itself is not an lvalue. The expression a is an lvalue. And the function does not return the variable: it returns the variable's value.
So, as I understand it there are two misconceptions involved in the question:
The idea that lvalue/rvalue is about objects. It's about expressions.
The idea that A foo() { return... } return a reference to an object (as in e.g. Java). It returns a value.
An lvalue is an expression that refers to a memory location and allows us to take the address of that memory location via the & operator. An rvalue is an expression that is not an lvalue.
See here http://thbecker.net/articles/rvalue_references/section_01.html
In your example, you're returning a copy of a stack allocated instance. But that is likely also on the stack and is a 'temporary copy', hence you cannot take the address of it. Hence it's not an lvalue, therefore it's an rvalue
When you do this:
int square(int& x) { return x*x;};
int s = square(40); // This gives error
To fix this you do this:
int square(const int& x) { return x*x;};
int s = square(40); // This is OK
I understand that 40 is a constant but so what if I do this:
const int& x = 40
Why would that be okay only with const keyword? Is that the way the compiler protect that no one can change the value referred to by x?
40 is a const so we don't even know its location in memory, but shouldn't the compiler know this address, therefore changing the value from 40 to 30 for example should be allowed since the compiler can just go to address &40 and change the value to 30?
Just because it's possible to implement doesn't mean you should do it. Having 40 really be 30 is hilarious but especially unmaintainable and should not be permitted. In addition, 40 doesn't necessarily actually have an address. Consider a 40 in cache, register, or an immediate instruction.
The declaration of square:
int square(int& x);
takes a lvalue, while invocation of square(40) takes a rvalue, this is inconsistent, see more of lvalue and rvalue here.
The rules about references is that you cannot bind a temporary to non-const lvalue reference. The literal 40 can be used to initialize a temporary but it is, itself, not an object. Thus, you cannot bind a non-const lvalue reference to it.
When you do
int const& value = 40;
you actually bind a temporary object initialized to be 40 to the reference value. Normally, temporaries go out of scope and are destroyed at the end of a full-expression. However, when you directly bind a temporary to a non-const reference its life-time is extended to match the life-time of the reference.
The rules prohibiting binding of temporary objects to non-const references is in place primarily because it would probably cause many surprising results. It could technically be done but would be quite likely to produce non-obvious results.
You're confusing constants and literals. They are similar, but not equivalent. 40 is not a constant, it's a literal.
You can't pass a literal by reference, since if you pass something by reference, it means it can be modified - literals cannot. Consider the following:
void foo(int &i)
{
i = 1;
}
foo(0); // What on Earth? 0 == 1?
If you, however, pass a reference to a constant, it means that even if it's a reference, the function is not permitted to modify its argument (since it's a constant), so now you can safely pass in a literal - it now makes sense, since there's no possibility for the function modifying its argument.
You can still do:
int x = 40;
int s = square(x)
x = 30;
s = square(x);
with both versions of square (the one or without const).
When you pass something by reference you are passing an existing object (because that is what a reference means an alias to an existing object).
In your example:
int s = square(30);
You are NOT passing an object. This is a literal (they are not objects). The compiler can convert literals into object by creating a temporary object. But the language has explicit restrictions on temporary object that mean they are const. This means references can not be passed to an interface where they will be mutated (though you can pass them by const reference).