Understanding lvalues and rvalues in C and C++
eli.thegreenplace.net
eli.thegreenplace.net
When exactly are move semantics and rvalue references useful, APART from using functions that return complex types. I am currently working on a codebase and I am really unsure if move semantics are something I really want to use. Sure, I'd love them for new projects, but if there are naming conventions and even conventions of passing result objects by pointer, not by reference (not my favourite rule), I don't think I'd like mixing styles. I think differently about starting to use "auto" and lambdas, but this is not about C++11 in general.
So actually I really wonder if there is a just case of rvalue references other than move constructors and returning by value. Any pointers?
"They’re not lvalues because both are temporary results of expressions, which don’t have an identifiable memory location (i.e. they can just reside in some temporary register for the duration of the computation)."
The problem is that lvalues _can_ "just reside in some temporary register for the duration of the computation". Any decent optimizing compiler will treat simple loop counters that way.
I am not even sure the C++ standard even mentions registers.
ldr r1,4 ;Load constant 4 into register 1
add r2,r2,r1 ;Add contents of r2 and r1, store in r2
ldr r1,5 ;Load constant 5 into register 1
where the value is only temporarily available for the single calculation. Even without thinking of registers, you can refer to the loop variable, but you can't refer to numbers in your operations.Maybe he could update this line for clarity, though.
With rvalue references, you can move around objects that should be moveable but not copyable. Consider an object representing a database connection - copying it isn't meaningful, but moving it ought to be.
It also follows the same rules in that 'rvalues are defined by exclusion.'
Bjarne Stroustrup, The C++ Programming Language, 2nd ed., p 47.
Left/right is so much easier to both remember and understand the terms.
What more accurately grasps the definition of lvalues and rvalues in C and C++ standards is that the former have an individual identity (concretely, they are permitted as the operand of the address-of operator &) and the latter don't. (Except don't get me started on the fact that in C++ one can overload operator&...)
"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’’."
An lvalue (locator value) represents an object that occupies some identifiable location in memory (i.e. has an address).
rvalues are defined by exclusion, by saying that every expression is either an lvalue or an rvalue.
So a pointer represents "an object that occupies some identifiable location in memory", meeting his definition of lvalue, and yet is a perfectly valid rvalue.
I sentence this person to be a teaching assistant for one term.
Edit: I love the first two replies to this comment:
1. No, lvalues are never rvalues by definition.
2. all lvalues are rvalues,
oh, maybe you meant an rvalue that happens to be a pointer? still makes sense, the pointer is not the same as what it points to.
[In light of Sharlin's comment, I should edit this to say that "lvalues are rvalues" is shorthand for "convertible to", the significance of the difference being what you make of it.]
I wonder if teaching from the standard is a better way of approaching this, ie: start with the standard, then just explain what it means.
Edit: Not to say we don't use gcc. The entire codebase does of course build using gcc on all of the platforms.. it is mainly the support issue and tweaks needed to build the binaries the way we want on each architecture.
int foo = 0, bar = 0;
(cond ? foo : bar) = 8;
This doesn't work in plain C. int foo = 0, bar = 0;
*(cond ? &foo : &bar) = 8;