WEBVTT

00:00:00.340 --> 00:00:04.090
This lesson will be a short digression where we will start discussing

00:00:04.090 --> 00:00:09.230
value categories in C++. To explain this abstract concept,

00:00:09.240 --> 00:00:13.320
I will introduce you to a series of simple programs. It is hard to

00:00:13.320 --> 00:00:17.230
explain what these value categories represent because they were expanded

00:00:17.230 --> 00:00:20.250
for the purpose of implementing move semantics,

00:00:20.260 --> 00:00:24.850
but to understand move semantics, you need to understand value categories.

00:00:25.340 --> 00:00:29.860
So, bear with me because I'm going to try to explain this in my own way.

00:00:30.240 --> 00:00:34.400
This simple program is declaring an integer variable and passing it as a

00:00:34.400 --> 00:00:38.860
reference to this function. We learned that references are just like the second

00:00:38.860 --> 00:00:43.480
identifiers used for accessing the same place in memory. So these two

00:00:43.480 --> 00:00:47.860
identifiers, x and num, x is the same place in memory.

00:00:48.540 --> 00:00:51.330
But what would happen if I tried to pass a simple

00:00:51.340 --> 00:00:53.660
integer literal to this function?

00:00:54.340 --> 00:00:57.730
This would not work because this number is not a variable,

00:00:57.740 --> 00:01:00.960
so it doesn't necessarily have its own place in memory.

00:01:01.340 --> 00:01:03.380
If I hover over this expression,

00:01:03.390 --> 00:01:07.420
you can see that my editor generated a special message, and you would get a

00:01:07.420 --> 00:01:11.810
similar one if you tried to compile this program. It says that the initial

00:01:11.810 --> 00:01:15.760
value of reference to a non‑const must be an lvalue.

00:01:16.140 --> 00:01:20.960
Let's ignore this lvalue for now and focus on this part that the reference

00:01:20.960 --> 00:01:24.750
to a non‑const initial value will not work in this case.

00:01:25.740 --> 00:01:29.550
So let's try to turn this reference into a constant reference.

00:01:29.940 --> 00:01:30.860
If I do this,

00:01:30.870 --> 00:01:35.370
the warning disappears. We can even try to compile this to make sure.

00:01:35.370 --> 00:01:39.140
Both values are printed out to the terminal, which means that the

00:01:39.140 --> 00:01:42.160
function also accepted a literal number.

00:01:42.540 --> 00:01:45.680
When we turn this reference into a constant reference,

00:01:45.680 --> 00:01:50.310
compiler will set aside a temporary place in memory for this number, 10, and

00:01:50.310 --> 00:01:53.550
then let us create a reference to that place in memory.

00:01:53.940 --> 00:01:56.800
But it will only do that if you use this const keyword

00:01:56.800 --> 00:01:59.470
because we cannot update the value of a number.

00:01:59.480 --> 00:02:03.810
The number itself is already a literal value, so its lifetime will be

00:02:03.810 --> 00:02:07.650
expanded until this reference is removed from the scope.

00:02:08.340 --> 00:02:11.970
So now this argument can accept both the values, which have an

00:02:11.970 --> 00:02:15.720
identity like this variable, and the values, which don't have

00:02:15.720 --> 00:02:18.060
an identity like this number 10.

00:02:19.440 --> 00:02:22.250
These are the first two value categories that we are going

00:02:22.250 --> 00:02:26.360
to talk about, the lvalues and prvalues.

00:02:26.740 --> 00:02:30.790
You can use the assignment operator as a mnemonic to help you remember

00:02:30.790 --> 00:02:36.140
which one is which. Lvalues, short for left values, are the values on the

00:02:36.140 --> 00:02:40.060
left, in this case, the values that have identity.

00:02:40.840 --> 00:02:47.090
Prvalues, or pure right values, are the values on the right, in this case,

00:02:47.100 --> 00:02:51.130
this integer literal that does not have an identity.

00:02:51.160 --> 00:02:54.280
I said that you can use this as a mnemonic tool, but you should

00:02:54.280 --> 00:02:58.740
not rely on lvalues always being on the left and prvalues on

00:02:58.740 --> 00:03:00.460
the right side of the statement.

00:03:01.240 --> 00:03:05.430
A better way to differentiate these two categories is to remember that

00:03:05.430 --> 00:03:08.460
lvalues always have a specific location in memory.

00:03:09.040 --> 00:03:15.430
So, a simple variable is an lvalue, pointer is an lvalue, reference is an

00:03:15.430 --> 00:03:19.860
lvalue, and also a function that returns a reference is an lvalue.

00:03:20.540 --> 00:03:24.650
Can we use the address‑of operator on all of these expressions?

00:03:25.440 --> 00:03:29.760
Yes, we can because all of them have a special place in memory.

00:03:30.140 --> 00:03:33.590
Even this expression has a place in memory because it's a function,

00:03:33.590 --> 00:03:36.960
which will first take in this non variable as a reference and then

00:03:36.960 --> 00:03:39.460
return a reference to that same variable.

00:03:40.340 --> 00:03:44.880
Of course, this syntax looks weird, but it works, which means that this

00:03:44.880 --> 00:03:48.560
expression evaluates to a value that has an identity.

00:03:49.640 --> 00:03:54.440
Prvalues are expressions, which evaluate to temporary values

00:03:54.450 --> 00:03:57.050
that don't have a special place on the stack.

00:03:57.540 --> 00:04:03.860
In this statement, only the number 5 is a prvalue, num variable is an lvalue.

00:04:04.240 --> 00:04:07.720
The same can be assumed for this second statement, but this whole

00:04:07.720 --> 00:04:11.160
expression will evaluate to a temporary number, 10.

00:04:12.040 --> 00:04:16.420
So this is an lvalue. This is a prvalue, but the result of this

00:04:16.420 --> 00:04:21.200
expression is also a prvalue because it only exists here, and it

00:04:21.200 --> 00:04:23.050
doesn't have a special identity.

00:04:23.540 --> 00:04:26.740
Same goes for the object, which is instantiated from

00:04:26.740 --> 00:04:28.960
a specific user‑defined class.

00:04:29.070 --> 00:04:33.920
This expression by itself is a prvalue because this instantiated object

00:04:33.930 --> 00:04:37.250
is temporary until we assign it to something else.

00:04:38.640 --> 00:04:43.200
Now let's get back to the first program. I made some modifications.

00:04:43.210 --> 00:04:46.350
Now the function also brings out this simple message before

00:04:46.350 --> 00:04:48.560
it outputs the value from the reference.

00:04:49.340 --> 00:04:52.970
A simple reference like this one is also known as an lvalue

00:04:52.970 --> 00:04:56.830
reference because it usually refers to lvalues, but it can also

00:04:56.830 --> 00:04:59.660
refer to prvalues when we make it constant.

00:05:00.040 --> 00:05:05.000
C++11 introduced major changes in the language, and one of these changes

00:05:05.010 --> 00:05:10.620
is the existence of the so‑called rvalue references. Before C++11, we

00:05:10.620 --> 00:05:14.030
only had two categories, lvalues and rvalues.

00:05:14.030 --> 00:05:17.850
But since rvalue now doesn't mean the same thing it did before,

00:05:17.860 --> 00:05:22.360
let's just agree that for now rvalue is equal to prvalue.

00:05:22.740 --> 00:05:26.030
So an rvalue reference looks like this.

00:05:26.040 --> 00:05:31.070
We can define it by using two ampersand characters instead of one. And

00:05:31.070 --> 00:05:34.360
we don't have to make it constant because the whole purpose of rvalue

00:05:34.360 --> 00:05:39.140
references is to point to temporary values like the prvalues we talked

00:05:39.140 --> 00:05:43.970
about. But the real reason for their existence is the ability to use

00:05:43.970 --> 00:05:45.960
them in function overloads.

00:05:47.140 --> 00:05:50.300
I will overload this function with another function,

00:05:50.300 --> 00:05:54.040
which will be able to accept an rvalue reference instead

00:05:54.040 --> 00:05:56.260
of a constant lvalue reference.

00:05:56.940 --> 00:06:00.660
The definition is the same, except for this special message.

00:06:01.640 --> 00:06:05.960
Now, let's compile this again. As you can see, the number

00:06:05.960 --> 00:06:09.670
variable is still passed to the first function, but the integer

00:06:09.670 --> 00:06:12.660
literal is using the overloaded function.

00:06:12.670 --> 00:06:16.490
Even though this first function is perfectly capable of accepting both

00:06:16.500 --> 00:06:21.380
lvalues and prvalues, if the argument is a temporary prvalue,

00:06:21.390 --> 00:06:26.460
compiler will always choose the overloaded function with an rvalue reference.

00:06:26.840 --> 00:06:29.940
This is actually great because now we can define a special

00:06:29.940 --> 00:06:32.750
function behavior for each value category.

00:06:33.140 --> 00:06:35.880
Lvalues will always use the first function, and

00:06:35.880 --> 00:06:38.560
prvalues will always use the second one.

00:06:39.240 --> 00:06:42.540
Hopefully, now you know the difference between lvalues and

00:06:42.540 --> 00:06:46.650
prvalues, and you also know what rvalue references are.

00:06:47.240 --> 00:06:50.090
But before we learn about other value categories,

00:06:50.090 --> 00:06:54.190
we have to know what moving means in C++, so we will continue

00:06:54.190 --> 00:06:56.560
this discussion in the next two lessons.
