WEBVTT

00:00:00.640 --> 00:00:05.740
Copy semantics allow us to make deep copies of objects, but in some situations,

00:00:05.750 --> 00:00:09.160
we would get a better performance from a shallow copy instead.

00:00:09.540 --> 00:00:12.080
Let's get back to genetic engineering.

00:00:12.120 --> 00:00:16.160
Here I have two new subjects, a chicken and a lizard.

00:00:17.040 --> 00:00:19.280
I want to have anzu as a subject,

00:00:19.290 --> 00:00:24.260
but I don't have its genetic material so I just declared it as an empty object.

00:00:24.740 --> 00:00:26.000
In case you don't know,

00:00:26.000 --> 00:00:29.190
anzu is some kind of a dinosaur that looked like a

00:00:29.190 --> 00:00:31.550
combination of a chicken and a lizard.

00:00:31.940 --> 00:00:34.640
So since dinosaurs don't exist anymore,

00:00:34.650 --> 00:00:37.570
I figured that I could combine these two subjects to make

00:00:37.570 --> 00:00:40.850
one because that's how biology works, right?

00:00:41.740 --> 00:00:42.790
And of course,

00:00:42.790 --> 00:00:45.760
this will not work because we didn't define a plus

00:00:45.760 --> 00:00:48.060
operator for the Subject class.

00:00:48.940 --> 00:00:50.260
Let's do that now.

00:00:52.440 --> 00:00:57.560
The subject_id of this new object will be the sum total of these two objects.

00:00:58.540 --> 00:01:01.250
Then I will create an array of four characters,

00:01:01.250 --> 00:01:05.560
which will replace the string literal we usually pass to create new subjects.

00:01:05.940 --> 00:01:08.490
The genetic code of this new subject will be the

00:01:08.490 --> 00:01:11.550
combination of sequences from both objects.

00:01:11.650 --> 00:01:14.450
The first two bases are taken from the chicken,

00:01:14.460 --> 00:01:17.060
and the next two are taken from the lizard.

00:01:17.440 --> 00:01:18.460
And finally,

00:01:18.460 --> 00:01:21.110
we can use these variables to instantiate a new

00:01:21.110 --> 00:01:23.860
subject and return it from the function.

00:01:24.640 --> 00:01:29.160
Notice that I made this reference constant, and now you know why.

00:01:30.140 --> 00:01:34.330
Because in case someone decides to add more than two subjects,

00:01:34.340 --> 00:01:36.260
this operator would still work.

00:01:36.740 --> 00:01:40.860
The subject we returned from this operator function is a prvalue,

00:01:40.860 --> 00:01:44.650
because it has no identity yet. It is just a new,

00:01:44.660 --> 00:01:45.960
unassigned object.

00:01:47.340 --> 00:01:50.410
And if we didn't make this parameter constant,

00:01:50.420 --> 00:01:54.890
then this new operator call would not be able to accept it because

00:01:54.890 --> 00:01:58.650
non‑constant references only accept L values.

00:01:59.440 --> 00:02:04.260
Okay, and now this operator is finished, so let's get back to the main function.

00:02:05.040 --> 00:02:07.100
When this expression gets evaluated,

00:02:07.110 --> 00:02:11.460
a new subject will be created and assigned to this anzu object.

00:02:11.840 --> 00:02:16.080
But remember that this expression alone will result in a temporary object,

00:02:16.080 --> 00:02:17.820
which is a PR value.

00:02:17.830 --> 00:02:19.660
When I compile this program,

00:02:19.660 --> 00:02:23.560
the copy assignment operator will make a deep copy of this object.

00:02:24.240 --> 00:02:26.070
To make sure that this actually happens,

00:02:26.080 --> 00:02:29.660
I will add a special message to the copy constructor and

00:02:29.670 --> 00:02:32.160
also to the copy assignment operator.

00:02:32.840 --> 00:02:36.350
This way we will know when one of them is used by the program.

00:02:37.140 --> 00:02:38.550
And now, let's compile it.

00:02:39.540 --> 00:02:41.200
It all works as expected.

00:02:41.200 --> 00:02:44.050
The copy assignment will make a deep copy of an object,

00:02:44.060 --> 00:02:46.950
and anzu will have a new genetic sequence.

00:02:47.840 --> 00:02:51.050
But why do we need a deep copy in this situation?

00:02:51.050 --> 00:02:54.990
After all, the result of this addition is a temporary object,

00:02:54.990 --> 00:02:58.860
which will disappear as soon as the program goes past this statement.

00:02:59.240 --> 00:03:02.220
So why don't we just steal the sample pointer from this

00:03:02.220 --> 00:03:05.020
prvalue object and give it to anzu,

00:03:05.020 --> 00:03:09.890
the dinosaur? Working with temporary prvalues in this way will

00:03:09.890 --> 00:03:12.840
improve the performance of the whole program.

00:03:12.850 --> 00:03:14.540
To define this special behavior,

00:03:14.540 --> 00:03:19.260
we would have to know when this assignment operator works with prvalues.

00:03:19.640 --> 00:03:22.960
Fortunately, we learned this in the previous lesson.

00:03:23.340 --> 00:03:26.210
To define a special behavior for temporary values,

00:03:26.220 --> 00:03:30.450
we can overload a function, which will take in an rvalue reference.

00:03:31.840 --> 00:03:35.260
In this case, we need to overload the assignment operator.

00:03:36.340 --> 00:03:39.220
The definition will look similar to the copy assignment,

00:03:39.230 --> 00:03:41.980
but instead of making a copy of this genetic code,

00:03:41.990 --> 00:03:46.450
we will just steal a pointer to the genetic code of this temporary object.

00:03:47.440 --> 00:03:50.950
In other words, this is just like a shallow copy.

00:03:51.340 --> 00:03:55.450
Of course, we need to again check if this subject is assigned to itself,

00:03:55.460 --> 00:03:58.750
and also return the object itself as a reference.

00:03:59.540 --> 00:04:00.650
Nothing new here.

00:04:01.240 --> 00:04:04.150
Before stealing the address from the other object,

00:04:04.160 --> 00:04:07.700
I also need to delete the DNA object at which this sample

00:04:07.700 --> 00:04:10.780
pointer points to because if I don't do that,

00:04:10.790 --> 00:04:12.240
we would have a memory leak.

00:04:12.940 --> 00:04:16.149
And finally, when we steal everything from this object,

00:04:16.160 --> 00:04:22.070
I will completely destroy it by setting its id to 0 and its sample to a nullptr.

00:04:22.370 --> 00:04:25.160
This is done to make sure that some other part of the program

00:04:25.160 --> 00:04:28.410
doesn't mess with this temporary object after we steal its

00:04:28.410 --> 00:04:32.460
pointer because we don't want to share the ownership or the DNA

00:04:32.460 --> 00:04:34.960
object under any circumstances.

00:04:35.340 --> 00:04:37.840
Maybe that seems unlikely in this situation,

00:04:37.840 --> 00:04:42.540
but you will see that we can also use this operator on values with identity.

00:04:42.550 --> 00:04:43.860
But more on that later.

00:04:44.640 --> 00:04:46.620
The assignment operator, like this one,

00:04:46.620 --> 00:04:50.290
which uses an rvalue reference to steal from temporary object,

00:04:50.300 --> 00:04:53.760
is also known as a move assignment operator.

00:04:54.740 --> 00:04:58.870
Creating a shallow copy of an object, which we then invalidate,

00:04:58.880 --> 00:05:03.650
can be seen as moving all of the resources from one object to another.

00:05:04.340 --> 00:05:08.750
Move assignment operator is part of the so‑called move semantics.

00:05:09.840 --> 00:05:13.330
It is a good practice to mark this operator with noexcept

00:05:13.340 --> 00:05:16.350
to let the other parts of the program know that this

00:05:16.350 --> 00:05:18.860
function is resilient to exceptions.

00:05:19.240 --> 00:05:24.200
And this is not only a good practice, I urge you to do this because if you don't,

00:05:24.210 --> 00:05:28.430
some STL containers will not be able to use this operator properly.

00:05:28.440 --> 00:05:30.060
But more on this later.

00:05:30.640 --> 00:05:33.760
Now let's compile this program to see if it works.

00:05:34.440 --> 00:05:35.480
And it does.

00:05:35.490 --> 00:05:38.640
You can see that the move assignment operator was used

00:05:38.650 --> 00:05:40.560
instead of the copy alternative.

00:05:41.240 --> 00:05:44.520
We know that copy semantics assume the existence of the copy

00:05:44.520 --> 00:05:47.190
constructor and copy assignment operator,

00:05:47.200 --> 00:05:51.950
so to implement move semantics, we also need to create a move constructor.

00:05:52.540 --> 00:05:56.740
I will move this expression up to the declaration of the object so that we can

00:05:56.750 --> 00:06:00.360
immediately initialize it by the result of this combination.

00:06:01.240 --> 00:06:03.780
This should use the constructor because this

00:06:03.780 --> 00:06:06.070
statement does an implicit conversion.

00:06:06.080 --> 00:06:09.160
It is actually making a call to the copy constructor.

00:06:10.540 --> 00:06:15.640
But let's overload this constructor to make one that works with prvalues.

00:06:15.650 --> 00:06:18.460
In other words, let's make a move constructor.

00:06:19.940 --> 00:06:23.090
Move constructor will receive an rvalue reference,

00:06:23.100 --> 00:06:27.260
and I will also mark it as a function which throws no exceptions.

00:06:27.640 --> 00:06:29.290
Just like in the assignment,

00:06:29.300 --> 00:06:33.960
we are making a shallow copy by stealing the values from all data members.

00:06:34.340 --> 00:06:35.140
But of course,

00:06:35.140 --> 00:06:38.320
we cannot forget to also destroy this temporary object

00:06:38.320 --> 00:06:41.360
by invalidating all of its resources.

00:06:42.240 --> 00:06:43.120
And that's it.

00:06:43.130 --> 00:06:44.160
Nothing special.

00:06:45.340 --> 00:06:47.210
If I compile this program now,

00:06:47.220 --> 00:06:50.950
the move constructor should be used to create the anzu object,

00:06:51.940 --> 00:06:54.410
but it isn't, and to make things worse,

00:06:54.410 --> 00:06:58.890
copy constructor was not used either because if it was, we

00:06:58.890 --> 00:07:02.610
would see its special message. Join me in the next lesson

00:07:02.610 --> 00:07:04.150
to see why this happened.
