Hello again! In this video, I'm going to look at reference and value semantics. Although another
title for this could be "Why does C++ not have a garbage collector?"
This is quite controversial - or, some people seem to get pretty worked up about it.
So let's find out what's going on.
We saw in the last video that C++ will copy objects unless you tell it to use a reference.
So that's known as value semantics.
A lot of languages use reference semantics, such as Java, C#, Python and so on.
This means that when you initialize an object from another object, or you pass an object to a function
call, you don't get a new object.
Instead, you get a reference to the original object.
So the program doesn't allocate - (oops, getting a bit motion sick here!)
So the program doesn't allocate new memory and copy the data into this new object.
Instead, we have an object which shares the memory, which was used by the original object.
Obviously, the program needs to make sure that the original object will stay around for as long as all
these other objects are sharing their memory with it.
And you can have lots of different objects which are all sharing the same memory.
So in order to keep track of all these different objects and decide whether it's safe to destroy them,
the language provides something called a "garbage collector."
So this is something that runs inside the program.
It keeps track of all the objects in it.
So when a completely new object is created, the garbage collector will know about it.
When another object is created, which is a reference to the object the garbage collector will record
that there is a reference to that object.
So basically, it keeps track of all the objects and the relationships between them.
And every so often, the program will stop executing.
The garbage collector will go through all the objects and decide which ones are still being used and
which ones are not.
And then it'll decide which ones it can delete, and then it will also decide whether it's safe to release
the memory or if there's still some other object which is using that object's memory.
So this avoids having to copy the object's data, and re-initialize the objects. As I said before,
that can take quite a long time, if an object has a lot of data in it, or if it needs to allocate memory
or get some information over the network. That can add to the execution time.
On the other hand, this garbage collection adds quite a bit of time itself. It does a lot of processing,
and it also uses a lot of memory, because it has to keep details of all these objects and all these relationships.
When the garbage collector is going through and checking the objects, the phone has to stop executing.
So that's just "dead time" as far as the program is concerned.
When an object is destroyed, its memory is not released immediately.
It won't be released until there are no other objects which are using that memory.
And even then, it won't be released until the garbage collector has run and decided that it can be
released.
So this means you can't predict when objects are actually finally destroyed and the memory is released.
And you also don't know what order the objects are going to be destroyed in.
So in C++, as we already know, this uses value semantics by default. If you press an object to a
function, it's passed by value by default.
If you initialize an object from another object, you get a completely new object, which is a copy
of the old one.
And also, objects only exist within a scope.
Well, that's for stack objects.
We can also have objects which are on the heap which live longer than that, but I'll come to that in a
minute.
If we decide we want to have reference semantics for our objects, we can provide that. We can pass arguments
by reference instead of by value.
We can use references, so that when we create a new object, it can be an alias to an existing object.
And if we do want something which lives for longer than the scope that it is defined in, we can allocate
it on the heap.
So that's using new, or possibly malloc for the C version.
And this is a typical Bjarne Stroustrup quote! "C++ does not have garbage collection because it
does not produce so much garbage"
So what are the advantages and disadvantages of C++'s way of doing things? Copying objects creates overhead
due to copying the objects data.
And that's particularly bad if you have a temporary object because you have something that just briefly
passes into existence, but you have to copy all it's data.
So that's an extra lot of copying. As we'll see, modern C++ has ways to reduce that.
On the other hand, there isn't any overhead from garbage collection.
You don't have the garbage collector using up memory or making your program stop.
Local variables are destroyed deterministically. So you know that there will be destroyed in a given order,
which is the reverse order that they were created in. And they're destroyed
synchronistically; when the program reaches the end of the scope, all the local variables are destroyed.
And that means that the memory that they're using becomes immediately available. On the other hand,
if you want to have an object that lives beyond its scope,
you have to allocate memory.
And usually that means you have to manage the memory and its lifetime yourself.
Although in modern C++, there are ways of avoiding that, using smart pointers.
OK, so that's it for this video.
I'll see you next time.
But meanwhile, keep coding!