Reputation: 8401
First example
int a = 0;
auto && b = ++a;
++a;
cout << a << b << endl;
prints 22
Second example
int a = 0;
auto && b = a++;
++a;
cout << a << b << endl;
prints 20
Question:
Why in first example ++a
in 3rd line also increments b
, and why there is no such behavior in second example?
Update: New question arised.
Upvotes: 5
Views: 181
Reputation: 141554
The difference is that ++a
is an lvalue, however a++
is not. This is specified by C++14 [expr.pre.incr]/1:
The operand of prefix
++
is modified by adding 1 [...] The operand shall be a modifiable lvalue. [...] The result is the updated operand; it is an lvalue
and [expr.post.incr]/1:
[...] The result is a prvalue.
Now we consider auto && b = ++a;
. ++a
is an lvalue. auto&&
is a forwarding reference. Forwarding references can actually bind to lvalues: the auto
may itself deduce to a reference type. This code deduces to int &b = ++a;
.
When a reference is bound to an lvalue of the same type, the reference binds directly, so b
becomes another name for a
.
In the second example, auto && b = a++;
, a++
is a prvalue. This means it doesn't have an associated address and it's no longer any relation to the variable a
. This line has the same behaviour as ++a; auto && b = (a + 0);
would.
Firstly, since a++
is a prvalue, auto&&
deduces to int&&
. (i.e. auto
deduces to int
). When a reference of non-class type is bound to a prvalue, a temporary object is copy-initialized from the value. This object has its lifetime extended to match the reference.
So b
in the second case is bound to a different object from a
, a "temporary" int (which is not really so temporary, since it lasts as long as b
does).
The reference binding rules are in [dcl.init.ref].
Upvotes: 3
Reputation: 33579
Because pre-increment (++a
) first increments the value of a
, stores the result, and then returns the reference to a
. Now a
and b
effectively point to the same object.
Post-increment (a++
), however, first stores the current value of a
in a temporary, increments a
, and returns this temporary - to which your rvalue ref points. a
and b
point to different objects, more specifically - b
is a temporary holding the value of a
prior to incrementing.
This is the reason why it's encouraged to use ++it
over it++
for iterators and other complex objects that define increment / decrement: the latter creates a temporary copy and thus may be slower.
Upvotes: 10
Reputation: 2703
In the second case (post-increment) b actually references the temporary created for (a++), so the increments do not affect b.
Upvotes: 1