Now that we know about references and how to use them,
let's look at l-values and r-values.
L-values into r-values are something you don't worry about too much
when you're first learning c++.
But as you learn more advanced features of the language,
they become very important.
It's important that the fundamentals make sense now so that when we
move on to topics like c++11, r-value references and move
semantics, they'll be much clearer.
So in this video, we'll do a basic introduction to l-values,
r-values and l-value references.
So let's start with an l-value.
An l-value is an object that occupies a location in
memory and is addressable.
So in these examples, x and name are l-values.
They have names, and they're addressable.
We know that they're addressable since we can use them on the left-hand
side of an assignment statement.
So what's not an l-value.
In these examples, 100 is not an l-value because it's not
addressable, it's a literal.
In fact, the compiler generates a compiler error for the 100
equals x statement, saying that 100 is not an assignable l-value.
Similarly, in the assignment statement 1000 plus 20 equals x,
1000 plus 20 produces a temporary variable with the value 1020, but
that variable is not addressable.
So we can't use it as an l-value.
In the last assignment statement, Frank equals name.
Well, Frank is not an l-value since it's not addressable.
So these examples are of non-l-values.
They're, in fact, called r-values.
Let's talk a bit about r-values.
We can define r-values by exclusion.
So anything that's not an l-value is an r-value.
Usually, r-values on the right-hand side of an assignment expression.
R-values can also be temporary values that the c++ compiler creates.
We saw some examples of r-values in the previous slide,
let's see a few more here.
In the first statement, 100 is an r-value.
In the second statement, x plus 200 will produce a temporary
variable and that variable is an r-value since it's not addressable.
The string literal Frank is also an r-value, and max 2030 is an r-value
because it returns a result that's a temporary and not addressable.
R-values can be assigned to l-values explicitly.
So l-values can appear both on the left and right sides
of an assignment statement.
In this example, we see the first assignment statement is using
the r-value 100 on the right-hand side of the assignment statement.
And this will be assigned to the l-value y.
In the second example, the temporary r-value with the sum x plus y
will be assigned to the l-value x.
Now let's look at references from the perspective of l-values and r-values.
The references we've used so far have all been l-value references.
That means that we're referring to l-values.
In the first reference declaration, we're declaring
ref1 as a reference to x.
Notice that x is an l-value.
This makes sense since we are an alias for x, and we can
use ref1 on the left-hand side of an assignment statement
since it refers to an l-value.
But what happens when we declare ref2 as a reference to 100.
Well, 100 is an r-value, so this isn't allowed, and the
compiler will generate an error.
The same applies when we pass parameters by reference to functions.
In this case, we define a function square that expects
an integer by reference.
We have an integer num initialized to 10, and then we
call square and pass in num.
This is fine because n is a reference to an l-value and num is an l-value.
However, if we pass in the literal 5 to the function, we
get a compiler error because 5 is not an l-value, it's an r-value
and we must reference l values.
Don't worry if this is a bit confusing now.
As you'll learn more about c++ semantics, it'll make more sense,
but it's important going forward when we talk about move semantics.