WEBVTT

00:02.060 --> 00:07.370
Hello again! In this video, I'm going to look at  reference and value semantics. Although another

00:07.370 --> 00:11.060
title for this could be "Why does C++ not have a garbage collector?"

00:11.870 --> 00:15.530
This is quite controversial - or, some people seem to get pretty worked up about it.

00:15.540 --> 00:17.510
So let's find out what's going on.

00:19.610 --> 00:26.210
We saw in the last video that C++ will copy objects unless you tell it to use a reference.

00:26.540 --> 00:28.100
So that's known as value semantics.

00:29.210 --> 00:35.000
A lot of languages use reference semantics, such as Java, C#, Python and so on.

00:35.600 --> 00:41.930
This means that when you initialize an object from another object, or you pass an object to a function

00:41.930 --> 00:43.910
call, you don't get a new object.

00:44.270 --> 00:46.970
Instead, you get a reference to the original object.

00:48.530 --> 00:52.580
So the program doesn't allocate - (oops, getting a bit motion sick here!)

00:53.960 --> 00:58.730
So the program doesn't allocate new memory and copy the data into this new object.

00:59.450 --> 01:04.850
Instead, we have an object which shares the memory, which was used by the original object.

01:06.260 --> 01:10.940
Obviously, the program needs to make sure that the original object will stay around for as long as all

01:10.940 --> 01:13.400
these other objects are sharing their memory with it.

01:13.850 --> 01:16.700
And you can have lots of different objects which are all sharing the same memory.

01:22.840 --> 01:29.770
So in order to keep track of all these different objects and decide whether it's safe to destroy them,

01:30.520 --> 01:33.430
the language provides something called a "garbage collector."

01:34.330 --> 01:37.210
So this is something that runs inside the program.

01:37.720 --> 01:39.380
It keeps track of all the objects in it.

01:39.400 --> 01:45.370
So when a completely new object is created, the garbage collector will know about it.

01:46.330 --> 01:52.060
When another object is created, which is a reference to the object the garbage collector will record

01:52.060 --> 01:54.280
that there is a reference to that object.

01:55.450 --> 01:58.780
So basically, it keeps track of all the objects and the relationships between them.

02:00.490 --> 02:03.520
And every so often, the program will stop executing.

02:04.300 --> 02:09.850
The garbage collector will go through all the objects and decide which ones are still being used and

02:09.850 --> 02:10.600
which ones are not.

02:12.920 --> 02:17.540
And then it'll decide which ones it can delete, and then it will also decide whether it's safe to release

02:17.540 --> 02:22.940
the memory or if there's still some other object which is using that object's memory.

02:28.840 --> 02:35.740
So this avoids having to copy the object's data, and re-initialize the objects. As I said before,

02:35.740 --> 02:40.990
that can take quite a long time, if an object has a lot of data in it, or if it needs to allocate memory

02:40.990 --> 02:45.430
or get some information over the network. That can add to the execution time.

02:46.330 --> 02:51.340
On the other hand, this garbage collection adds quite a bit of time itself. It does a lot of processing,

02:51.820 --> 02:56.470
and it also uses a lot of memory, because it has to keep details of all these objects and all these relationships.

02:57.940 --> 03:02.680
When the garbage collector is going through and checking the objects, the phone has to stop executing.

03:03.010 --> 03:06.100
So that's just "dead time" as far as the program is concerned.

03:09.060 --> 03:12.690
When an object is destroyed, its memory is not released immediately.

03:12.960 --> 03:17.280
It won't be released until there are no other objects which are using that memory.

03:18.000 --> 03:23.160
And even then, it won't be released until the garbage collector has run and decided that it can be

03:23.160 --> 03:23.640
released.

03:24.420 --> 03:29.310
So this means you can't predict when objects are actually finally destroyed and the memory is released.

03:30.090 --> 03:33.450
And you also don't know what order the objects are going to be destroyed in.

03:37.850 --> 03:43.580
So in C++, as we already know, this uses value semantics by default. If you press an object to a

03:43.580 --> 03:46.250
function, it's passed by value by default.

03:47.180 --> 03:52.190
If you initialize an object from another object, you get a completely new object, which is a copy

03:52.190 --> 03:53.150
of the old one.

03:53.870 --> 03:56.150
And also, objects only exist within a scope.

03:56.720 --> 03:58.910
Well, that's for stack objects.

03:59.360 --> 04:04.310
We can also have objects which are on the heap which live longer than that, but I'll come to that in a

04:04.310 --> 04:04.610
minute.

04:06.320 --> 04:12.470
If we decide we want to have reference semantics for our objects, we can provide that. We can pass arguments

04:12.470 --> 04:14.060
by reference instead of by value.

04:15.620 --> 04:20.840
We can use references, so that when we create a new object, it can be an alias to an existing object.

04:21.890 --> 04:27.500
And if we do want something which lives for longer than the scope that it is defined in, we can allocate

04:27.500 --> 04:28.130
it on the heap.

04:28.490 --> 04:32.330
So that's using new, or possibly malloc for the C version.

04:34.530 --> 04:40.920
And this is a typical Bjarne Stroustrup quote! "C++ does not have garbage collection because it

04:40.920 --> 04:42.570
does not produce so much garbage"

04:49.980 --> 04:56.280
So what are the advantages and disadvantages of C++'s way of doing things? Copying objects creates overhead

04:56.280 --> 04:58.050
due to copying the objects data.

04:58.950 --> 05:04.380
And that's particularly bad if you have a temporary object because you have something that just briefly

05:04.380 --> 05:08.010
passes into existence, but you have to copy all it's data.

05:08.370 --> 05:14.190
So that's an extra lot of copying. As we'll see, modern C++ has ways to reduce that.

05:15.590 --> 05:18.200
On the other hand, there isn't any overhead from garbage collection.

05:18.680 --> 05:22.190
You don't have the garbage collector using up memory or making your program stop.

05:24.020 --> 05:30.380
Local variables are destroyed deterministically. So you know that there will be destroyed in a given order,

05:30.650 --> 05:35.450
which is the reverse order that they were created in. And they're destroyed

05:35.480 --> 05:41.150
synchronistically; when the program reaches the end of the scope, all the local variables are destroyed.

05:43.380 --> 05:49.470
And that means that the memory that they're using becomes immediately available. On the other hand,

05:49.470 --> 05:52.030
if you want to have an object that lives beyond its scope,

05:52.050 --> 05:53.340
you have to allocate memory.

05:53.730 --> 05:58.080
And usually that means you have to manage the memory and its lifetime yourself.

05:58.650 --> 06:03.510
Although in modern C++, there are ways of avoiding that, using smart pointers.

06:07.250 --> 06:09.200
OK, so that's it for this video.

06:09.770 --> 06:10.710
I'll see you next time.

06:10.760 --> 06:13.280
But meanwhile, keep coding!
