The prefix operators return the object
itself as an lvalue. The postfix operators return a copy of the object’s original value
as an rvalue.
so in a statement like so *a++ a is being incremented and a copy of the original value of a is returned as rvalue but from the microsoft c++ language reference on Lvalues and Rvalues
An rvalue is a temporary value that does not persist beyond the expression that uses it
and gives an example
// lvalues_and_rvalues1.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main()
{
int x = 3 + 4;
cout << x << endl;
}
In this example, x is an lvalue because it persists beyond the expression that defines it. The expression 3 + 4 is an rvalue because it evaluates to a temporary value that does not persist beyond the expression that defines it.
My questions:
1) what is the rvalue being returned from the *a++ so that it can be dereferenced?
2) Did i misunderstand any concept ?
Thanks in advance!
The prefix operators return the object itself as an lvalue. The postfix operators return a copy of the object’s original value as an rvalue.
Wrong! Well, mostly. If the quote is talking about all prefix/suffix operators, then it's completely errated. However, if it's talking about the ++ and -- prefix/postfix pairs, then it's correct.
Now, taking that into account...
what is the rvalue returning from the *a++ so that it can be dereferenced?
Assuming a is a pointer of some kind, a++ increments a and yields a rvalue consisting of a's value before the increment. The increment and decrement operators, ++ and --, in both postfix and prefix forms, require an lvalue as their operator. This is because rvalues are temporary, that is, their scope is limited by the expression their occur in, so these operators make little or no sense on them. Remember, these operators not only inspect/read, but change/write to the variable itself.
The unary * operator takes a pointer(-like) object and dereferences it, yielding an lvalue found in there. It works for both rvalue and lvalue pointers. This is because * can be considered sort of a "passive" operator. It does not change/write to the pointer itself, but dereferences it and returns the lvalue object at the address stored by the pointer, whose address is of course that contained by the pointer. As all that * needs is the memory address contained in a pointer object, and the address of the pointer itself, if it has one at all, is useless here, * makes sense for both rvalues and lvalues.
You can think that * "requires an rvalue", and that "lvalues can be used as rvalues when necessary", if it clarifies (or confuses?) things a little bit more.
*a++ is equivalent to:
auto temp = *a;
a++;
// Use the value of temp here
except you can only refer to the value once, where as temp you could refer to multiple times.
Related
Code
#include<iostream>
int main()
{
int a=3;
a++=5;
std::cout<<a;
}
Output (as expected)
[Error] lvalue required as left operand of assignment
1. The post increment operator (a++) has the highest priority in the table. So it will definitely execute before the assignment operator (=). And as per the rule of post increment the value of variable a will increment only after execution of that statement.
So what exactly happens when the post increment operator (++)
executes before the assignment operator (=)?
2.
In C both the pre- and post-increment operators yield rvalues but C++ updated the pre-increment operator to an lvalue while keeping the post-increment operator as an rvalue only. The reason for that is we can't make it an lvalue as it possesses only the old value, not the updated one. But I don't understand this reason properly.
See now a++ has the rvalue 3, not the variable itself, right? But what if it brings a variable which possesses an lvalue, then 5 will insert into that and after the end of the statement its value will be 6. What's the problem with this and why can't it be done?
And As per rule of post increment the value of variable a will increment only after execution of that statement.
That's a bit misleading. The variable is incremented immediately. But the result of the expression is the old value. This should make it easier to understand why it cannot be an lvalue. The modified object doesn't have the old value, so the hypothetical lvalue cannot refer to that object. The value is a new, temporary object; it is a prvalue.
As an analogy, think about writing a function that does the same thing as post increment. This is how it would be written (if you define overloaded operator overload for a class, then a function such as this is quite literally what you'd write with a few changes):
int post_increment(int& operand)
{
int old = operand;
operand += 1;
return old;
}
How could you meaningfully re-write that function to return an lvalue (reference) and still have the behaviour expected from the post increment?
I noticed in C++ that something like++++i is allowed and increments i by 2. However, i++++ is not allowed. Why is the latter not allowed whereas the former is?
The result of postfix ++ is a prvalue. Postfix ++ can only be applied to modifiable lvalue. So you can't apply postfix ++ to the result of another postfix ++. This makes sense because it needs some object to modify. The result of the operator is just a value (a copy of the original value of the operand) - there's no object for you to modify.
On the other hand, the result of prefix ++ is an lvalue and it also expects an lvalue as its operand. Therefore you can pass the result of a prefix ++ to another ++.
It might help for you to think about lvalues as denoting objects in memory and rvalues as just values (that may have come from an object in memory). Postfix ++ expects an lvalue because it wants an object that it can modify. It returns an rvalue because the result is just a value not associated with any object (because it was copied from the operand before modification). Prefix ++ also wants to modify its operand, so also expects an lvalue. However, it returns the object after modification, which is the operand object itself and so its result is an lvalue too.
Given:
int& foo(); // don't care what the reference is to
int intVal;
In the following two cases the right hand side is the same function call
int& intRef = foo();
intVal = foo(); // a reference is returned... a value is assigned.
In the second case how is the returned reference "converted" into a value?
Is it done by the assignment operator for the int?
At the language level there's no such concept as "dereferencing a reference". A reference implements the concept of an lvalue. A variable and a reference are basically the same thing. The only difference between a variable and a reference is that the variable is bound to its location in storage automatically, by the compiler, while a reference is generally bound through user action at run time.
In your example, there's no conceptual difference between intRef and intVal. Both are lvalues of type int. And at the conceptual level both are accessed through the same mechanism. You can even think of all variables in your program as references, which were implicitly pre-bound for you by the compiler. This is basically what Bjarne Stroustrup means in TC++PL when he says (not verbatim) that one can think of references as just alternative names for existing variables.
The only moment when the difference between the two is perceptible is when you create these entities and initialize them. Initialization of a reference is an act of binding it to some location in storage. Initialization of a variable is an act of copying the initial value into the existing storage.
But once a reference is initialized, it acts as an ordinary variable: an act of reading/writing a reference is an act of reading/writing the storage location it is bound to. Taking the address of a reference evaluates to the address of the storage location it is bound to. And so on.
It is not a secret that in many cases a reference is implemented internally as a pointer in disguise, i.e. as an invisible pointer that is implicitly dereferenced for you every time you access it. In such cases (when it is really implemented through a pointer) the dereference is done, again, every time you access it. So, it is not the assignment operator that does it, as you ask in your question. It is the very fact that you mentioned the name of that reference in your code that causes the invisible pointer to get dereferenced.
However, an entity that implements "alternative name for existing variable" does not necessarily require storage for itself, i.e. in a compiled language it is not required to be represented by anything material, like a hidden pointer. This is why the language standard states in 8.3.2 that "It is unspecified whether or not a reference requires storage".
foo is returning some reference to an object of type "int". We won't care about where that "int" came from and we'll just assume it exists.
The first line, int& intRef = foo(), creates intRef which also refers to exactly the same object of type "int" as is referenced by the return value of foo.
The second line, the value of intVal is replaced by the value of the object referred to by the returned reference.
In response to your comments:
You seem to be getting very confused between pointers and references. References are just like aliases for an object. Doing anything to a reference will actually affect the object it refers to.
There is no such thing as dereferencing a reference. You can only dereference pointers. Dereferencing is the act of using the unary * operator to get the object pointed at by a point. For example, if you have a int* p, you can do *p to get the object that it points at. This is dereferencing p.
The only time you can do * on a reference is if the object it refers to is a pointer (or if it overloads operator*). In your case, since foo returns an int&, we can't dereference it. The expression *foo() just won't compile. That's because the return value of foo has type "int" which is not a pointer and doesn't overload operator*.
For all intents and purposes, you can treat the reference returned from foo as simply being the object it refers to. Assigning this value to intVal is really no different to assigning x to intVal in the following code:
int intVal;
int x = 5;
intVal = x;
As I'm sure you understand, intVal is given the value of x. This is defined simply by the standard:
In simple assignment (=), the value of the expression replaces that of the object referred to by the left operand.
No conversion needs to occur at all because both sides of the operator are the same type.
This is really no different to your situation. You just have:
intVal = some_ref_to_int;
Where some_ref_to_int is the expression foo(). The fact that it's a reference doesn't matter. intVal receives the value of the object that the reference denotes.
Assigning to intVal is an assignment-expression defined in 5.17 [exp.ass] in the standard. The grammar rules for an assignment-expression are quite complicated, depending on several other grammar rules, but basically you need a modifiable lvalue on the left hand side of the = operator, and a prvalue expression on the right hand side.
In the case of
intVal = foo();
the expression on the RHS is an lvalue of type int, so the built-in lvalue-to-rvalue conversion takes place ... this is barely a conversion, in that the value doesn't change and neither does the type (except that for fundamental types cv-qualifiers are removed, so if the lvalue is type const int the prvalue will be type int). [conv.lval] says
A glvalue (3.10) of a non-function, non-array type T can be converted to a prvalue. [...] If T is a non-class type, the type of the prvalue is the cv-unqualified version of T. Otherwise, the type of the prvalue is T. [...] the value contained in the object indicated by the glvalue is the prvalue result.
So the prvalue has type int and the same value as foo() i.e. the same value as the variable the returned reference is bound to.
The rules of assignment expressions say:
In simple assignment (=), the value of the expression replaces that of the object referred to by the left operand.
So the value of intVal will be replaced by the value of the prvalue. The rules continue:
If the left operand is not of class type, the expression is implicitly converted (Clause 4) to the cv-unqualified type of the left operand.
So because int is not a class type (and therefore has no overloaded operator= it just uses the built-in assignment operator) the assignment will convert the RHS to int, which is the type it already has in your case.
So the value of intVal gets set to the value of the prvalue, which we said is the value of the glvalue expression foo(), i.e. the value of the variable the reference is bound to.
Note that the lvalue-to-rvalue conversion is nothing to do with the RHS being a reference. The same thing happens here:
int val = 0;
intVal = val;
val is an lvalue of type int so it's converted to a prvalue of type int and the value of intVal is set to the value of that prvalue.
The rules are expressed in terms of an expression's "value category" (i.e. lvalue or rvalue) not whether it's a reference or not. Any "dereferencing" of a reference that's needed is done implicitly and invisibly by the compiler in order to implement the required behaviour.
For example:
int x[100];
void *p;
x[0] = 0x12345678;
x[1] = 0xfacecafe;
x[3] = 0xdeadbeef;
p = x;
((int *) p) ++ ;
printf("The value = 0x%08x", *(int*)p);
Compiling the above generates an lvalue required error on the line with the ++ operator.
The cast creates a temporary pointer of type int *. You can't increment a temporary as it doesn't denote a place to store the result.
In C and C++ standardese, (int *)p is an rvalue, which roughly means an expression that can only occur on the right-hand side of an assignment.
p on the other hand is an lvalue, which means it can validly appear on the left-hand side of an assignment. Only lvalues can be incremented.
The expression ((int *) p) treats the pointer stored inside the variable p is a pointer to int. If you want to treat the variable itself as a pointer to int variable (and then increment it), use a reference cast:
((int *&) p) ++ ;
Thanks to larsmans for pointing to the right direction.
I took the liberty of digging deeper into this. So for future reference, according to sections 6.5.2.4 and 6.5.4 of the C99 standard (http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf):
6.5.2.4 Postfix increment and decrement operators
Constraints
The operand of the postfix increment
or decrement operator shall have
qualified or unqualified real or
pointer type and shall be a modifiable
lvalue....
6.5.4 Cast operators
..
..
[Footnote] 89) A cast
does not yield an lvalue. Thus, a cast
to a qualified type has the same
effect as a cast to the unqualified
version of the type.
Note: This only applies to C. C++ may handle casts differently.
You can get the intended result with
p = (int*)p + 1;
Using the increment operator on a dereferenced pointer to p, which is an lvalue, also works:
(*(int**)&p)++;
However, the latter is not portable, since (void*)p might not have the same representation as (int*)p.
Rvalue expression ((int *) p) creates and temporary of type int* on which operator ++ cannot be applied.
++ requires an lvalue as its operand.
As #FredOverflow mentions lvalues and rvalues have very little to do with assignment.
Arrays are lvalues still they cannot be assigned to because they are non-modifiable.
std::string("Prasoon") is an rvalue expression still it can occur on the left side of assignment operator because we are allowed to call member functions( operator = in this case) on temporaries.
In C++, pre-increment operator gives lvalue because incremented object itself is returned, not a copy.
But in C, it gives rvalue. Why?
C doesn't have references. In C++ ++i returns a reference to i (lvalue) whereas in C it returns a copy(incremented).
C99 6.5.3.1/2
The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation. The expression ++Eis equivalent to (E+=1).
‘‘value of an expression’’ <=> rvalue
However for historical reasons I think "references not being part of C" could be a possible reason.
C99 says in the footnote (of section $6.3.2.1),
The name ‘‘lvalue’’ comes originally
from the assignment expression E1 =
E2, in which the left operand E1 is
required to be a (modifiable) lvalue.
It is perhaps better considered as
representing an object ‘‘locator
value’’. What is sometimes called
‘‘rvalue’’ is in this International
Standard described as the ‘‘value of
an expression’’.
Hope that explains why ++i in C, returns rvalue.
As for C++, I would say it depends on the object being incremented. If the object's type is some user-defined type, then it may always return lvalue. That means, you can always write i++++++++ or ++++++i if type of i is Index as defined here:
Undefined behavior and sequence points reloaded
Off the top of my head, I can't imagine any useful statements that could result from using a pre-incremented variable as an lvalue. In C++, due to the existence of operator overloading, I can. Do you have a specific example of something that you're prevented from doing in C, due to this restriction?