WEBVTT

00:00:00.640 --> 00:00:04.350
There comes a time in a life of every genetic engineer when

00:00:04.350 --> 00:00:07.150
he needs to create a clone of a sheep.

00:00:07.840 --> 00:00:13.150
I assume that's like a hello world of genetic engineering, but I might be wrong.

00:00:13.640 --> 00:00:17.750
Creating a clone in our program should be straightforward.

00:00:18.140 --> 00:00:21.990
I can declare the new sheepClone variable and initialize it

00:00:21.990 --> 00:00:24.760
with the already existing sheep subject.

00:00:25.140 --> 00:00:29.000
I didn't want to complicate things by validating unique IDs, so

00:00:29.000 --> 00:00:31.760
let's just assign some other ID to the clone.

00:00:32.140 --> 00:00:35.400
And finally, let's print the clone's data to see if our

00:00:35.400 --> 00:00:37.560
cloning experiment was successful.

00:00:38.540 --> 00:00:39.650
Let's compile this.

00:00:40.640 --> 00:00:43.990
It seems that the clone was initialized correctly, both of

00:00:43.990 --> 00:00:46.460
the sheep have the same genetic sequence.

00:00:46.840 --> 00:00:47.410
However,

00:00:47.410 --> 00:00:51.200
something also went terribly wrong, since we also got this

00:00:51.200 --> 00:00:55.680
Segmentation fault, but let's ignore this error for a second

00:00:55.690 --> 00:00:57.850
and continue like nothing's wrong.

00:00:58.540 --> 00:01:00.930
Since we already created a clone,

00:01:00.940 --> 00:01:04.170
let's modify its genetic sequence by changing the first

00:01:04.170 --> 00:01:06.850
two chemical bases to something else.

00:01:08.040 --> 00:01:12.070
I will change the first base to guanine and the second one to

00:01:12.070 --> 00:01:16.070
cytosine. After the modification, I will again print the data

00:01:16.070 --> 00:01:18.560
from both subjects to compare them.

00:01:19.340 --> 00:01:21.760
Let's now recompile this program.

00:01:22.640 --> 00:01:26.010
It looks like the modification worked, the clone has a

00:01:26.010 --> 00:01:30.940
different sequence, but it seems like the original sheep was

00:01:30.940 --> 00:01:35.560
also affected. By modifying the clone, we also changed the

00:01:35.560 --> 00:01:38.450
genetic code of the original subject.

00:01:38.940 --> 00:01:41.750
This is one of the problems we have to face when working with

00:01:41.750 --> 00:01:44.660
pointers to dynamically allocated resources.

00:01:45.040 --> 00:01:49.660
To examine the root of this issue, let's start from this declaration statement.

00:01:50.040 --> 00:01:54.680
When you initialize a new object at the point of declaration by using this

00:01:54.690 --> 00:02:00.800
equals character, C++ will apply implicit conversion. It will implicitly

00:02:00.800 --> 00:02:04.560
convert this whole statement to a constructor call.

00:02:05.540 --> 00:02:10.460
So, this statement is actually completely identical to this one.

00:02:10.840 --> 00:02:15.530
We are calling the subject's constructor, which accepts another subject

00:02:15.540 --> 00:02:19.610
as a parameter, but we didn't define this constructor,

00:02:19.620 --> 00:02:24.350
we only have two constructors and none of them accept an object of this type.

00:02:24.740 --> 00:02:25.430
However,

00:02:25.440 --> 00:02:28.260
this will still work, because the compiler will

00:02:28.260 --> 00:02:30.560
define this constructor by default.

00:02:30.940 --> 00:02:34.260
This predefined constructor looks something like this.

00:02:35.140 --> 00:02:38.710
It takes in a reference to an object of the same type, and

00:02:38.710 --> 00:02:42.530
then it uses that reference to copy all of its members to

00:02:42.530 --> 00:02:44.650
our newly instantiated one.

00:02:45.040 --> 00:02:46.010
In other words,

00:02:46.020 --> 00:02:49.910
this constructor creates a clone of another object by literally

00:02:49.910 --> 00:02:52.960
taking all of the values from its data members.

00:02:53.340 --> 00:02:58.390
The reason why compiler defines this constructor is because we want to make our

00:02:58.390 --> 00:03:02.460
user‑defined classes work similar to primitive data types.

00:03:02.940 --> 00:03:07.700
If you declared an integer by initializing it with another integer variable,

00:03:07.700 --> 00:03:12.360
you would expect that the value gets copied over from one variable to another.

00:03:13.140 --> 00:03:17.990
The same expectation stands for the user‑defined classes, and creating a copy

00:03:17.990 --> 00:03:22.160
from the object of the same type is really common practice.

00:03:22.540 --> 00:03:27.690
This is why this constructor is known as the copy constructor, because it

00:03:27.690 --> 00:03:32.910
literally creates a copy of another object. In the first module, I said that

00:03:32.910 --> 00:03:36.760
whenever you pass an argument to the function by value,

00:03:36.770 --> 00:03:39.910
that function will create a local copy of the value and

00:03:39.910 --> 00:03:42.750
store it inside of the parameter variable.

00:03:43.040 --> 00:03:46.410
So the reason why we pass this other object by reference

00:03:46.420 --> 00:03:48.980
isn't just for optimization purposes,

00:03:48.990 --> 00:03:53.260
it is also because it makes no sense to pass this other object by value.

00:03:53.640 --> 00:03:57.440
Imagine if we did that, if this was not a reference,

00:03:57.450 --> 00:04:01.840
what would happen? Since this object is passed by value, that means

00:04:01.840 --> 00:04:05.120
that this function needs to create a copy of the sheep object and

00:04:05.120 --> 00:04:07.950
store it inside of this other parameter.

00:04:08.440 --> 00:04:13.130
But the exact process of creating a copy is defined by this copy

00:04:13.130 --> 00:04:18.000
constructor, so we are defining a copy constructor by invoking that

00:04:18.000 --> 00:04:21.250
same copy constructor, and that makes no sense.

00:04:21.640 --> 00:04:26.480
This is also why a copy constructor is important, because it's invoked whenever

00:04:26.480 --> 00:04:32.580
you pass the objects by value. We also make this reference constant because we

00:04:32.580 --> 00:04:35.350
have no reason to change this original object.

00:04:35.840 --> 00:04:39.650
There is also another purpose for doing this, but we'll talk about that later.

00:04:40.340 --> 00:04:44.610
This definition of a copy constructor is more than enough for some classes,

00:04:44.620 --> 00:04:48.840
but not for this subject class, because we are using a pointer

00:04:48.840 --> 00:04:51.560
which points to the DNA object on the heap.

00:04:51.940 --> 00:04:56.280
So, first we create the original sheep object, which will allocate a new

00:04:56.280 --> 00:05:01.340
DNA object on the heap, and we will store its location inside of the

00:05:01.340 --> 00:05:04.990
sample pointer. Then, we declare the clone,

00:05:04.990 --> 00:05:08.450
bypassing this original sheep to the copy constructor.

00:05:09.840 --> 00:05:14.320
This copy constructor makes a copy of values from all of the original

00:05:14.320 --> 00:05:19.620
sheep members, and this is where the problems begin. Copy constructor

00:05:19.620 --> 00:05:23.470
will literally copy the value from the sample pointer of the original

00:05:23.470 --> 00:05:26.350
sheep to the sample pointer of the clone.

00:05:26.740 --> 00:05:30.350
So both of these sheep have the sample pointer which

00:05:30.350 --> 00:05:32.700
points to the same place in memory.

00:05:32.790 --> 00:05:36.600
The clone didn't allocate another DNA sequence on the heap,

00:05:36.610 --> 00:05:39.250
it just points to the same address in memory.

00:05:39.640 --> 00:05:43.520
When we modify the DNA sequence through the sample pointer of a clone,

00:05:43.530 --> 00:05:48.360
we are actually modifying the DNA object allocated by the original sheep.

00:05:49.340 --> 00:05:52.490
And, since both sheep own that same DNA,

00:05:52.500 --> 00:05:55.640
the original sequence will be changed too, because

00:05:55.650 --> 00:05:58.060
there is only the original sequence.

00:05:59.140 --> 00:06:01.880
This is the same reason why we get the segmentation

00:06:01.880 --> 00:06:04.260
fault at the end of the program.

00:06:05.240 --> 00:06:07.420
Once the scope of the main function is over,

00:06:07.430 --> 00:06:11.790
all of the subjects will be destroyed, and as we know, before that

00:06:11.790 --> 00:06:15.150
happens, the program will first call their destructors.

00:06:15.540 --> 00:06:18.900
So when the program calls the destructor of the original sheep,

00:06:18.910 --> 00:06:22.050
this DNA sequence will be deallocated from the heap.

00:06:22.640 --> 00:06:25.160
We did that to prevent a memory leak.

00:06:25.540 --> 00:06:26.270
However,

00:06:26.270 --> 00:06:30.950
the sample pointer from the clone is still pointing to this non‑existent DNA

00:06:30.950 --> 00:06:36.330
sequence, so when its destructor gets called, the program will try to deallocate

00:06:36.340 --> 00:06:40.290
that DNA again, and since it doesn't exist anymore,

00:06:40.300 --> 00:06:42.250
we will get a segmentation fault.

00:06:43.040 --> 00:06:48.430
So now you see why implementing RAII in classes is more complicated

00:06:48.430 --> 00:06:51.760
than just allocating and deallocating memory.

00:06:52.140 --> 00:06:55.710
But now that we know what the problem is, the solution is simple.

00:06:55.950 --> 00:07:00.410
We just need to allocate another DNA object for the clone and then copy the

00:07:00.410 --> 00:07:05.620
sequence from the original sheep to that new DNA. To do that, I will pass the

00:07:05.620 --> 00:07:09.750
DNA object itself by dereferencing the sample pointer.

00:07:10.840 --> 00:07:15.040
And, we are allowed to do that because DNA class also has its

00:07:15.050 --> 00:07:18.360
own copy constructor, defined by the compiler.

00:07:18.740 --> 00:07:22.230
I can hover over this expression to show you. This

00:07:22.230 --> 00:07:24.860
constructor does look familiar, right?

00:07:25.240 --> 00:07:29.190
It is the DNA's copy constructor which will literally copy the

00:07:29.190 --> 00:07:34.530
code array from this DNA object. Since I already defined other

00:07:34.530 --> 00:07:38.700
constructors with the member initializer list, let's do the same

00:07:38.700 --> 00:07:40.460
for this copy constructor.

00:07:41.240 --> 00:07:45.050
You don't have to, but I think that this makes our intention clearer.

00:07:46.040 --> 00:07:46.540
Okay,

00:07:46.550 --> 00:07:52.100
let's see if this fixed something, and it seems like it did. We no longer

00:07:52.100 --> 00:07:55.720
get a segmentation fault, and the sequence of the original sheep is

00:07:55.720 --> 00:07:58.860
preserved after the modification of the clone.
