WEBVTT

00:00.150 --> 00:00.690
Hello again!

00:01.050 --> 00:04.260
In this video, we are going to start looking at move semantics.

00:05.770 --> 00:12.460
When we implemented the swap() function, we saw that sometimes we can speed things up by exchanging data,

00:12.760 --> 00:14.080
instead of copying objects.

00:14.560 --> 00:19.850
For example, with the string argument, we could just swap over the memory buffers which contain

00:19.870 --> 00:25.720
the data. And that was much faster than copying all the characters from one object to another. Move

00:25.780 --> 00:31.240
semantics is something a bit like that, except it concerns function arguments and function return

00:31.240 --> 00:35.170
values, rather than the internals of the swap implementation.

00:37.610 --> 00:42.800
C++ often uses value semantics, which means there is a lot of data copying going on.

00:43.730 --> 00:48.290
For example, with function calls. By default, arguments are passed by value, which means copying them,

00:48.650 --> 00:52.220
and they are returned by value, which again means copying them.

00:53.240 --> 00:56.390
With the containers in the Standard Template Library.

00:56.990 --> 00:59.120
These copy data into their elements.

01:00.560 --> 01:05.870
You are not allowed to use references, so you cannot have a container of references.

01:06.320 --> 01:09.920
And the reason for that, is that it is too easy to create "dangling" references.

01:10.520 --> 01:15.560
If you store a local variable in a container element and then return from the function, the container

01:15.560 --> 01:17.750
has a reference to something which does not exist.

01:18.970 --> 01:20.200
You can use pointers.

01:20.230 --> 01:23.230
But again, with local variables, you may get dangling pointers.

01:23.860 --> 01:29.860
If you allocate the pointer on the heap, then you have to manage it and you can get all the usual problems,

01:30.280 --> 01:31.480
including memory leaks.

01:36.050 --> 01:41.900
The reason why value semantics was chosen, was that it avoids the need for a garbage collector.

01:42.350 --> 01:47.840
And in the days when C++ was being devised as a very efficient object-oriented language, garbage

01:47.840 --> 01:49.160
collectors were very slow.

01:50.190 --> 01:54.600
However, it does mean a lot of copying of objects, which increases the execution time.

01:54.870 --> 01:59.310
And there have been various attempts to do something about this. In traditional C++,

01:59.550 --> 02:05.340
the compiler can "elide" copies when it is returning temporary and local variables from a function.

02:05.820 --> 02:12.750
And we looked at copy elision earlier on. And modern C++ has "move semantics", which is another attempt

02:12.750 --> 02:14.310
to ameliorate things.

02:15.370 --> 02:17.500
As an example of how much time this can save.

02:17.830 --> 02:19.540
Let's imagine we have this code.

02:19.540 --> 02:23.830
We have a local variable, which is a vector of 1 million strings.

02:25.150 --> 02:31.540
We pass this variable by value into a function, which is perhaps not the best design, but it's only

02:31.540 --> 02:32.110
an example!

02:32.920 --> 02:36.610
And then we never actually use the original variable again in this scope.

02:37.390 --> 02:38.440
So what will happen here?

02:39.280 --> 02:44.110
The function call will cause the copy constructor to be called for 1 million strings.

02:44.500 --> 02:49.360
And at the end of the scope, when the variable is destroyed, there will be 1 million calls to the

02:49.360 --> 02:50.440
string destructor.

02:52.990 --> 02:58.210
So this code goes to lots of trouble to make sure that "vec" is still a valid object after being passed

02:58.210 --> 02:58.960
to the function.

02:59.410 --> 03:01.720
But in fact, it is all wasted, because we never use it again.

03:03.310 --> 03:07.930
So if there was some way to get this data, the 1 million strings, out of the vector and into the

03:07.930 --> 03:11.230
function call argument, then we could save a lot of time.

03:13.040 --> 03:16.970
So in this case, the function call would not cause any memory allocation.

03:17.840 --> 03:22.850
The data in the vector is moved into the function argument. And that will leave this "vec" variable

03:22.850 --> 03:27.260
as an empty vector, and destroying it is going to take no time at all.

03:31.110 --> 03:33.390
C++11 introduced move semantics.

03:33.660 --> 03:39.600
This is an optimisation over copying objects, which can be used in some cases: if the object being copied

03:39.600 --> 03:41.310
is something called an "rvalue".

03:42.300 --> 03:47.460
And in that case we can just move its data into the target, the function argument, instead of copying

03:47.460 --> 03:47.670
it.

03:48.510 --> 03:51.180
So this is a bit like moving files between folders.

03:52.470 --> 03:58.890
If you are in a file manager, and you have some file in a folder, and you want to have this file in a different

03:58.890 --> 04:00.810
folder, you could copy it.

04:01.200 --> 04:06.270
So the operating system will make a new file and copy the data from the old file into the new file.

04:07.260 --> 04:13.200
Or alternatively, you can move the file. And if it is on the same disk, then the actual data will

04:13.200 --> 04:18.480
stay in the same place on the disk, and the operating system will just change the name of the file.

04:18.930 --> 04:22.080
So it now has a different file in a different folder, but the same data.

04:24.920 --> 04:29.510
So some diagrams, finally, just to show you the difference between these three ways of doing things.

04:29.900 --> 04:35.660
So with copying, if we are copying this string2 into string1, each element is going to be copied

04:35.660 --> 04:37.940
into the elements of string1.

04:41.430 --> 04:47.840
With swapping, the two memory buffers of these strings are going to be swapped over. So the buffer

04:47.850 --> 04:54.570
from string1 will end up in string2, and string1 will get the old buffer from string2.

04:56.690 --> 05:03.020
If we move the data from string2 into string1, then string1's buffer will now be the old string2

05:03.020 --> 05:06.230
buffer, and string2 is going to have an invalid buffer.

05:07.850 --> 05:09.260
Okay, so that is it for this video.

05:10.130 --> 05:10.930
I will see you next time.

05:10.940 --> 05:13.160
But until then, keep coding!
