I am learning C++ and I found that when a reference is on the right hand side, there can be two cases. Suppose I have a method:
int& GetMe(int& i) { return i; }
And I have:
(1) int j; GetMe(j) = GetMe(i);
and
(2) int& k = GetMe(i);
The consequences of (1) and (2) are different. In (1), the semantic is to copy the value of i into j. The addresses of i and j are remained the same. Changing i doesn't affect j at all. Actually this is the case when you overload the index operator[] and use the index operator for assignment. In (2), the semantic is to create a referent of i as k. k has the same address as i and changing i affects k.
So why do we have the differences? I think, in C++, a reference's address is determined once and only once. Once a reference's address is determined, it can never be changed later. In (1), the reference of j is determined before, so the action is to copy value from i to j. In (2), the reference of k is being declared and initialized so it is done using reference of i. So the action is reference initialization.
I didn't find material explicitly saying above things so I want confirmation. Anyone knows reference well in C++ must can help me or point me to clear material. Thank you very much in advanced.
What you are missing here is that type of variable is different and it is all that matters. In first example you have int j and in second - int &k.
References in functions prototypes exists in different grounds, they looks the same, underneath they are pretty much the same but they used differently because they exists only when method is executing.
Actually, your code is dong exactly following
int j;
int & j1 = j;
int & i1 = i;
j1 = i1;
versus
int & i1 = i;
int & k = i1;
It's easy to see that in first case two references actually reference different variables i.e. different parts in memory but in second case they all reference the exact same variable. Hence the difference.
In case 1, GetMe returns a reference to j and you then assign a value to j through that reference. In case 2 GetMe returns a reference to i and then you assign that reference to another reference k meaning k refers to i.
References are immutable in C++ (meaning that you cannot change what a reference refers to, though you can change the value of the referent). Reference are also transparently substitutable for what they refer to when used on the right hand side of an expression. The immutability of references means that there is no ambiguity in 1 - you must intend to assign to what the return value of GetMe refers to rather than to change the reference. There is no ambiguity in 2 because you are assigning a reference to a reference (you can't assign an int to a reference to an int).
The difference is that in your second example you are defining a reference and in the first example, you are assigning to an existing reference.
Related
Is there a way to write something like below:
int i = 0;
int *p1 = &(i++);
int *p2 = &(++i);
Before asking "Is there a way", I think we have to ask, "What would it mean?"
In C, we have the concept of "object" versus "value". Basically, an object is a thing that can hold a value. So a variable like
int a;
is clearly an object, because it can hold a value — that is, we can say things like
a = 5;
to store a value into a.
The key distinction between an object and a value is that an object has a location. A value, on the other hand, is something we've computed that's just kind of floating in space, and if we don't find an object to store it in pretty soon, it disappears.
(Side note: You will sometimes come across the terms "lvalue" and "rvalue", which mean the same thing as "object" and "value" as I've been using them here. An lvalue is something that can appear on the left side of an assignment operator, while an rvalue is something that can only appear on the right.)
I've gone through this longish background introduction just so I can make this important point: You can only apply the address-of operator to an object, because only objects have locations. It makes perfect sense to say
int *p = &a;
But it would make no sense to say
int *p2 = &5; /* WRONG */
or
int *p3 = &(1 + 2); /* WRONG */
So it would equally make no sense to write
int *p4 = &(a + 1); /* WRONG */
The variable a is an object, but the thing that you get by fetching a's value and adding 1 to it is clearly just a value. By the time we've computed that value, it doesn't really matter (we might as well have forgotten) that one part of the computation of that value involved fetching a value from the object a.
But then we get you your questions. Suppose you try to write
int *p5 = &(i++); /* questionable */
int *p6 = &(++i);
The ++ operator takes a value and adds 1 to it, and the value i + 1 is clearly just a value, without a location. But, its true, i++ and ++i mean more than just "i + 1" — they compute the value i + 1 and store it back into i. So you can almost convince yourself that i++ and ++i have locations — but if they did, it would just be the location of the variable i. So you might as well have just said
int *p7 = &i;
Now, you might ask, "But what if I want to take the address of i, at the same time I increment it?" And the answer is, you're just going to have to do it in two steps:
int *p7 = &i;
i++;
Yes, it's true, the i++ and ++i operators are nice in that they let you do two things at once, things like
int x = array[i++];
or
int x = *p++;
But those are useful operations, because they come up all the time when you're working with arrays. But the need to say something like
int *p5 = &(i++);
comes up much less often, I think, so it's not nearly so important to have it work. (Me, I've been programming in C for 40 years, and I don't think I've ever felt the need to grab a pointer to i and increment it at the same time.) The ++ operator is something that often comes up in a loop, as i moves through an array or something. But since the address of i doesn't change, if you need a pointer to it, It makes sense to do that just once, before the loop (or whatever) even starts.
Finally, whether you agree with my explanations so far or not, the C Standard explicitly says that the result of the ++ and -- operators is an rvalue, not an lvalue. Two compilers I just tried this on gave me the errors
error: cannot take the address of an rvalue of type 'int'
and
error: lvalue required as unary ‘&’ operand
and these error messages pretty much say the same story I've been telling.
Although, to throw a pretty big monkey wrench into this story I've been telling, the rules are evidently different in C++! You can't do &(i++), but you can do &(++i)! I think there's a good reason for this, but I don't remember what it is.
I already know the question with this answer and apologize for the initial unclear question.
In C, we cannot use &(i++) and &(++i) and I think the reason is i++ and ++i are rvalues in C. However in C++, i++ is rvalue and ++i is lvalue.
In C++, the statement
int *p1 = &(i++);
will not work as i++ returns an rvalue and you cannot take the address of an rvalue.
On the other hand, the statement
int *p2 = &(++i);
is fine (i.e., it works). Check it out here.
i++ yields the value of i before being incremented and increments it.
If &(i++) were valid, it would mean take the address of the "previous value". Since i is the name we are using for a single memory location, where would that previous value go?
If you need the previous value of i, it needs to be stored somewhere before you can do anything with it including pointing to it.
int j = i++;
int *ip = &i;
int *jp = &j;
Then, *ip will yield the incremented value and *jp will yield the value before the increment.
Since ++i yields the incremented value of i, it works with just a single value. Still, for clarity, best to use separate statements for the increment and taking the address of the variable:
int *ip = &i;
++i;
even if the compiler allows &(++i) or even if it is legal (did not check). You are writing for the fellow programmer (who might be you), not the compiler.
The book said: Because references are not objects, we may not define a reference to a reference.
int ival = 1024;
int &refVal = ival;
refVal = 2;
int ii = refVal;
int &refVal3 = refVal; // isn't this a definition of ref to ref?
int i = refVal;
int &refVal4 = 10;
double dval = 3.14;
int &refVal5 = dval;
However, that line is not an error, because refVal3 is saying it is just another alias for refVal, and refVal is just another name for ival(refVal3 is bound to the object to which refVal is bound to, which is ival)... so both refVal and refVal3 refer to the initializer of ival.
That makes perfect sense, but if that's not a definition of a reference to a reference, just what exactly does the book mean when it mentioned "Because references are not objects, we may not define a reference to a reference." ??
Can someone perhaps give me an example ?
Your understanding is correct.
int &refVal3 = refVal;
This makes refVal3 a reference to the same thing refVal is a reference to. That is, ival.
just what exactly does the book mean when it mentioned "Because
references are not objects, we may not define a reference to a
reference." ?
A reference can only refer to an object. But references are not objects. So a reference cannot refer to a reference. And when the book says this, it doesn't just mean that it's not allowed, and you'll get an error if you try. But you can't even try. There's no syntax for it. Because anything you try to do to a reference, you will actually be doing to the object it refers to, and not to the reference itself.
Can someone perhaps give me an example ?
No. I can't. And that's the point. There's simply no syntax for it.
Reference-to-reference types (like T & &) do not exist in C++.
Where T is an object type (which includes int, as in your example):
You can have (lvalue) references to T. There exists a type T &.
You can have rvalue references to T. There exists a type T &&.
T && is not a reference to a reference; && is a single token and does not mean & &.
You cannot have references to references to T. There are no such types as T & &, T & &&, T && & or T && &&. If you write a declaration that attempts to explicitly name such a type, this is an error.
(Similarly, cv-qualified types like const T& exist, while types like const T & & do not exist.)
You asked for an example. Consider this wrong code:
int main()
{
int ival = 1024;
int &refVal = ival;
int & &refRefVal = refVal; // wrong
}
This is an error because there is no such type as int & &. It would be an error regardless of what I tried to initialize it with.
(Strictly speaking, it is an error because the syntax of the language prohibits it. The standards committee could have chosen to allow me to write int & & and have it mean the same thing as int &--see Reference Collapsing below--but they didn't, which is good, because that would be very confusing.)
When I attempt to compile that wrong code with Clang 3.8, I get:
error: 'refRefVal' declared as a reference to a reference
Other compilers give similar errors. For example, Microsoft Visual C++ gives:
error C2529: 'refRefVal': reference to reference is illegal
When you use a reference, the effect is to use the object it refers to.
References are dereferenced automatically in most contexts where they appear. Anything you try to do to a reference, really you are doing it to the object it refers to. Unlike pointers, there is no operator for dereferencing a reference; in effect the reference is a name for the referenced object.
What you have written (int &refVal3 = refVal;) is not an error, because you are simply initializing a second reference bound to the same object. To see why this is, consider the effect of several of your statements.
Here you create an int, initializing it with the value 1024:
int ival = 1024;
Here you make an lvalue reference, bound to that int object:
int &refVal = ival;
Here you assign 2 to the original int object, because refVal is used as the object to which it refers:
refVal = 2;
Here you create a second int object, initialized with the value of the original object, also because refVal is used as the object to which it refers:
int ii = refVal;
Here you make a second lvalue reference to the original object, also because refVal is used as the object to which it refers:
int &refVal3 = refVal;
Code that looks like it creates a second reference to the first one is, therefore, really creating a second reference to the original object.
This is to say that the reason int &refVal3 = refVal; introduces another reference to the original object--rather than attempting to create a reference to a reference--is that this is just another consequence of refVal being automatically taken to mean the int it refers to.
Reference Collapsing
You can't write types named like T & & yourself, but what about this?
using Ref = int&;
using RefRef = Ref&; // I named this poorly, it's not really a reference to a reference!
This causes the compiler to see that I am trying to make a type alias RefRef to be int& &. The compiler follows the rules of reference collapsing. It collapses the two references into one, so the effect is the same as if I had written:
using RefRef = int&;
This behavior is useful in situations that involve type deduction, such as with templates, both by allowing more code to compile and work as expected than otherwise would, and by facilitating perfect forwarding. (One might argue it also parallels what you observed--when you initialize references from references, you can still never get a reference to a reference, only to an object.)
In no case is there ever anything whose type is reference to reference. The C++ language simply does not have any such types.
It is not possible to assign an integer value to a reference variable directly, say like:
int &x=10; //not possible
Is there any other way we can modify this statement to make it possible?
But not like this:
int a=10;int &x=a;
This works fine. But I want some other way or modify a little bit my expression and make it work!
The reference as the name says has to reference to something. How do you want to assign a value to it if it doesn't reference anything?
The reason it doesn't work is because 10 is of the type "const int". You can turn that into a reference, but you can't make it non-const without violating some logic at the least.
const int &a = 10;
that'll work.
int &b = const_cast<int &>(static_cast<const int &>(10));
will also compile, but you can't modify b (as that would imply modifying the actual "10" value).
The crux is that 10 is a constant – somewhat obviously: you cannot change its value. But if you try to assign it to an int reference, this would mean that the value were modifiable: an int& is a modifiable value.
To make your statement work, you can use a const reference:
int const& x = 10;
But as “cnicutar” has mentioned in a comment, this is pretty useless; just assign the 10 to a plain int.
You can't bind a reference-to-nonconst to anything immutable.
The standard permits storing compile time constants in ROM (btw, attempting to modify const_cast<>ed compile time constants yields undefined behaviour)
This would basically strip of the const, even if the const is invisible, therefore subverting the whole const-correctness-thing
However, you can bind a reference-to-const to nearly everything, including temporaries:
GotW: A candidate for the most important const
Consider this a "feature".
References refer to objects (perhaps temporary objects), not to values. If you want to store a value somewhere, assign it to an object, not to a reference.
As a special case, const int &a = 10; initializes the reference a to refer to a temporary object with the value 10, and it extends the lifetime of that temporary to the end of the scope of a (12.2/5). That's pretty useless with an integer literal, but occasionally useful with objects of class type. Still, this does not assign an integer value to a reference. It creates a temporary, and binds a reference to the temporary.
in the C++0x, you can use int&& (rvalue references ), but this can be used as function parameter.
I have a method:
odp(foo& bar);
I'm trying to call it:
foo baz;
odp(&baz);
I get a compiler error:
error C2664: "odp" cannot convert parameter 1 from 'foo *' to 'foo &'
What am I doing wrong? Aren't I passing in a reference to baz?
UPDATE: Perhaps I have a misconception about the relationship between pointers and references. I thought that they were the same, except references couldn't be null. Is that incorrect?
When you apply the unary & operator to an object, you get a pointer to that object, not a reference. You need a reference in this case. In order to initialize a reference parameter, you don't need to apply any operators at all: an lvalue object can immediately be used by itself to initialize a reference of the appropriate type.
The informal synonymity between the notions of "pointer" and "reference" (as in "pass by pointer" and "pass by reference") is specific to C language. But in C++ they mean two completely different things.
The odp function need a reference to a foo var whereas you are passing the adress of a foo var (pointer).
Just pass baz like:
foo baz;
opd(baz);
And it will compile.
No, you're passing a pointer to baz. Drop the &.
When you use &baz, you are actually saying address of baz, so you are passing a pointer.
References and pointers are NOT the same in C++ - although you have probably read that most compilers implement references using pointers at the machine-code level. You don't need to care how they are implemented by the compiler - but what the semantics of a "reference" and a "pointer" are in C++.
int i = 5;
int &j = i; // j refers to the variable i
// wherever the code uses j, it actually uses i
j++; // I just changed i from 5 to 6
int *pj = &i; // pj is a pointer to i
(*pj)--; // I just changed i back to 5
Note that I can change pj to point to another integer, but I cannot change the reference j to refer to another integer.
int k = 10;
pj = &k; // pj now actually points to k
(*pj)++; // I just changed k to 11
j = k; // no, this doesn't change the reference j to refer to k instead of i,
// but this statement just assigned k to i, that is, i now equals 11!
In C++, references are aliases, not addresses. You can, for instance, have multiple names for a single pointer, just as you might have multiple names for a single real object.
When you declare a function taking a reference parameter, the function will automatically alias whatever variable you pass to it. Whatever it aliases, though, must be of the same type as the reference. In your case, you are aliasing an int* with an int reference, which doesn't make sense.
Maybe you're being misled by old C conventions? In C, you "pass by reference" by creating a pointer, because the language doesn't have references - you use the pointer to "reference" the original variable. In C++, references are supported by the language and there's no need to create a pointer to the variable when you call the function.
foo baz;
odp(baz);
Why is ++i is l-value and i++ not?
Other people have tackled the functional difference between post and pre increment.
As far as being an lvalue is concerned, i++ can't be assigned to because it doesn't refer to a variable. It refers to a calculated value.
In terms of assignment, both of the following make no sense in the same sort of way:
i++ = 5;
i + 0 = 5;
Because pre-increment returns a reference to the incremented variable rather than a temporary copy, ++i is an lvalue.
Preferring pre-increment for performance reasons becomes an especially good idea when you are incrementing something like an iterator object (eg in the STL) that may well be a good bit more heavyweight than an int.
Well as another answerer pointed out already the reason why ++i is an lvalue is to pass it to a reference.
int v = 0;
int const & rcv = ++v; // would work if ++v is an rvalue too
int & rv = ++v; // would not work if ++v is an rvalue
The reason for the second rule is to allow to initialize a reference using a literal, when the reference is a reference to const:
void taking_refc(int const& v);
taking_refc(10); // valid, 10 is an rvalue though!
Why do we introduce an rvalue at all you may ask. Well, these terms come up when building the language rules for these two situations:
We want to have a locator value. That will represent a location which contains a value that can be read.
We want to represent the value of an expression.
The above two points are taken from the C99 Standard which includes this nice footnote quite helpful:
[ 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’’. ]
The locator value is called lvalue, while the value resulting from evaluating that location is called rvalue. That's right according also to the C++ Standard (talking about the lvalue-to-rvalue conversion):
4.1/2: The value contained in the object
indicated by the lvalue is the rvalue
result.
Conclusion
Using the above semantics, it is clear now why i++ is no lvalue but an rvalue. Because the expression returned is not located in i anymore (it's incremented!), it is just the value that can be of interest. Modifying that value returned by i++ would make not sense, because we don't have a location from which we could read that value again. And so the Standard says it is an rvalue, and it thus can only bind to a reference-to-const.
However, in constrast, the expression returned by ++i is the location (lvalue) of i. Provoking an lvalue-to-rvalue conversion, like in int a = ++i; will read the value out of it. Alternatively, we can make a reference point to it, and read out the value later: int &a = ++i;.
Note also the other occasions where rvalues are generated. For example, all temporaries are rvalues, the result of binary/unary + and minus and all return value expressions that are not references. All those expressions are not located in an named object, but carry rather values only. Those values can of course be backed up by objects that are not constant.
The next C++ Version will include so-called rvalue references that, even though they point to nonconst, can bind to an rvalue. The rationale is to be able to "steal" away resources from those anonymous objects, and avoid copies doing that. Assuming a class-type that has overloaded prefix ++ (returning Object&) and postfix ++ (returning Object), the following would cause a copy first, and for the second case it will steal the resources from the rvalue:
Object o1(++a); // lvalue => can't steal. It will deep copy.
Object o2(a++); // rvalue => steal resources (like just swapping pointers)
It seem that a lot of people are explaining how ++i is an lvalue, but not the why, as in, why did the C++ standards committee put this feature in, especially in light of the fact that C doesn't allow either as lvalues. From this discussion on comp.std.c++, it appears that it is so you can take its address or assign to a reference. A code sample excerpted from Christian Bau's post:
int i;
extern void f (int* p);
extern void g (int& p);
f (&++i); /* Would be illegal C, but C programmers
havent missed this feature */
g (++i); /* C++ programmers would like this to be legal */
g (i++); /* Not legal C++, and it would be difficult to
give this meaningful semantics */
By the way, if i happens to be a built-in type, then assignment statements such as ++i = 10 invoke undefined behavior, because i is modified twice between sequence points.
I'm getting the lvalue error when I try to compile
i++ = 2;
but not when I change it to
++i = 2;
This is because the prefix operator (++i) changes the value in i, then returns i, so it can still be assigned to. The postfix operator (i++) changes the value in i, but returns a temporary copy of the old value, which cannot be modified by the assignment operator.
Answer to original question:
If you're talking about using the increment operators in a statement by themselves, like in a for loop, it really makes no difference. Preincrement appears to be more efficient, because postincrement has to increment itself and return a temporary value, but a compiler will optimize this difference away.
for(int i=0; i<limit; i++)
...
is the same as
for(int i=0; i<limit; ++i)
...
Things get a little more complicated when you're using the return value of the operation as part of a larger statement.
Even the two simple statements
int i = 0;
int a = i++;
and
int i = 0;
int a = ++i;
are different. Which increment operator you choose to use as a part of multi-operator statements depends on what the intended behavior is. In short, no you can't just choose one. You have to understand both.
POD Pre increment:
The pre-increment should act as if the object was incremented before the expression and be usable in this expression as if that happened. Thus the C++ standards comitee decided it can also be used as an l-value.
POD Post increment:
The post-increment should increment the POD object and return a copy for use in the expression (See n2521 Section 5.2.6). As a copy is not actually a variable making it an l-value does not make any sense.
Objects:
Pre and Post increment on objects is just syntactic sugar of the language provides a means to call methods on the object. Thus technically Objects are not restricted by the standard behavior of the language but only by the restrictions imposed by method calls.
It is up to the implementor of these methods to make the behavior of these objects mirror the behavior of the POD objects (It is not required but expected).
Objects Pre-increment:
The requirement (expected behavior) here is that the objects is incremented (meaning dependant on object) and the method return a value that is modifiable and looks like the original object after the increment happened (as if the increment had happened before this statement).
To do this is siple and only require that the method return a reference to it-self. A reference is an l-value and thus will behave as expected.
Objects Post-increment:
The requirement (expected behavior) here is that the object is incremented (in the same way as pre-increment) and the value returned looks like the old value and is non-mutable (so that it does not behave like an l-value).
Non-Mutable:To do this you should return an object. If the object is being used within an expression it will be copy constructed into a temporary variable. Temporary variables are const and thus it will non-mutable and behave as expected.
Looks like the old value:This is simply achieved by creating a copy of the original (probably using the copy constructor) before makeing any modifications. The copy should be a deep copy otherwise any changes to the original will affect the copy and thus the state will change in relationship to the expression using the object.
In the same way as pre-increment:It is probably best to implement post increment in terms of pre-increment so that you get the same behavior.
class Node // Simple Example
{
/*
* Pre-Increment:
* To make the result non-mutable return an object
*/
Node operator++(int)
{
Node result(*this); // Make a copy
operator++(); // Define Post increment in terms of Pre-Increment
return result; // return the copy (which looks like the original)
}
/*
* Post-Increment:
* To make the result an l-value return a reference to this object
*/
Node& operator++()
{
/*
* Update the state appropriatetly */
return *this;
}
};
Regarding LValue
In C (and Perl for instance), neither ++i nor i++ are LValues.
In C++, i++ is not and LValue but ++i is.
++i is equivalent to i += 1, which is equivalent to i = i + 1.
The result is that we're still dealing with the same object i.
It can be viewed as:
int i = 0;
++i = 3;
// is understood as
i = i + 1; // i now equals 1
i = 3;
i++ on the other hand could be viewed as:
First we use the value of i, then increment the object i.
int i = 0;
i++ = 3;
// would be understood as
0 = 3 // Wrong!
i = i + 1;
(edit: updated after a blotched first-attempt).
The main difference is that i++ returns the pre-increment value whereas ++i returns the post-increment value. I normally use ++i unless I have a very compelling reason to use i++ - namely, if I really do need the pre-increment value.
IMHO it is good practise to use the '++i' form. While the difference between pre- and post-increment is not really measurable when you compare integers or other PODs, the additional object copy you have to make and return when using 'i++' can represent a significant performance impact if the object is either quite expensive to copy, or incremented frequently.
By the way - avoid using multiple increment operators on the same variable in the same statement. You get into a mess of "where are the sequence points" and undefined order of operations, at least in C. I think some of that was cleaned up in Java nd C#.
Maybe this has something to do with the way the post-increment is implemented. Perhaps it's something like this:
Create a copy of the original value in memory
Increment the original variable
Return the copy
Since the copy is neither a variable nor a reference to dynamically allocated memory, it can't be a l-value.
How does the compiler translate this expression? a++
We know that we want to return the unincremented version of a, the old version of a before the increment. We also want to increment a as a side effect. In other words, we are returning the old version of a, which no longer represents the current state of a, it no longer is the variable itself.
The value which is returned is a copy of a which is placed into a register. Then the variable is incremented. So here you are not returning the variable itself, but you are returning a copy which is a separate entity! This copy is temporarily stored inside a register and then it is returned. Recall that a lvalue in C++ is an object that has an identifiable location in memory. But the copy is stored inside a register in the CPU, not in memory. All rvalues are objects which do not have an identifiable location in memory. That explains why the copy of the old version of a is an rvalue, because it gets temporarily stored in a register. In general, any copies, temporary values, or the results of long expressions like (5 + a) * b are stored in registers, and then they are assigned into the variable, which is a lvalue.
The postfix operator must store the original value into a register so that it can return the unincremented value as its result.
Consider the following code:
for (int i = 0; i != 5; i++) {...}
This for-loop counts up to five, but i++ is the most interesting part. It is actually two instructions in 1. First we have to move the old value of i into the register, then we increment i. In pseudo-assembly code:
mov i, eax
inc i
eax register now contains the old version of i as a copy. If the variable i resides in the main memory, it might take the CPU a lot of time to go and get the copy all the way from the main memory and move it into the register. That is usually very fast for modern computer systems, but if your for-loop iterates a hundred thousand times, all those extra operations start to add up! It would be a significant performance penalty.
Modern compilers are usually smart enough to optimize away this extra work for integer and pointer types. For more complicated iterator types, or maybe class types, this extra work potentially might be more costly.
What about the prefix increment ++a?
We want to return the incremented version of a, the new version of a after the increment. The new version of a represents the current state of a, because it is the variable itself.
First a is incremented. Since we want to get the updated version of a, why not just return the variable a itself? We do not need to make a temporary copy into the register to generate an rvalue. That would require unnecessary extra work. So we just return the variable itself as an lvalue.
If we don't need the unincremented value, there's no need for the extra work of copying the old version of a into a register, which is done by the postfix operator. That is why you should only use a++ if you really need to return the unincremented value. For all other purposes, just use ++a. By habitually using the prefix versions, we do not have to worry about whether the performance difference matters.
Another advantage of using ++a is that it expresses the intent of the program more directly: I just want to increment a! However, when I see a++ in someone else's code, I wonder why do they want to return the old value? What is it for?
C#:
public void test(int n)
{
Console.WriteLine(n++);
Console.WriteLine(++n);
}
/* Output:
n
n+2
*/