Hello again! In this video, we are going to look at "copy and swap".
Copy and swap is another way to write an assignment operator for a class.
We create a local variable in the function body, which is a copy of the function argument.
We swap the contents of this local variable with the object that we are assigning to, the "this" object
or the object that "this" points to.
Then we can return this object, which now contains the assigned-to values. And when we return from
the function, this local variable is destroyed.
So let's break this down.
We start off by calling the copy constructor.
We pass the function argument to the copy constructor.
This could throw an exception.
If it does, then the destructors will be called for this scope.
The "temp" object will be destroyed. Then the function returns immediately.
The object we are assigning to is not modified.
We have not done anything to it yet.
And there is an exception for the caller to handle, which is normal when a constructor throws an exception.
If the constructor does not throw an exception, then this "temp" object now contains the values that we want to assign
to the "this" object.
So we just swap them around, we swap the data from the "temp" object and the "this" object.
swap() is noexcept, so this cannot throw any exceptions.
When this returns, "this" will have the data from the function argument and "temp" will have the data that
used to be in the "this" object.
And then finally, we have the right values in "this", so we return it.
So the usual way to return from assignment operators, we dereference the "this" pointer and the compiler
converts it to a reference.
Then when the function returns, the destructors are called, the "temp" object is destroyed, and that will
release all the resources that the original object was using.
So there are no memory leaks in this code.
So let's look at this.
So we have our String class again. The the rest of the class is exactly the same.
Here is our assignment operator, which performs a "copy and swap". There is the copy and there is the swap.
and then we return the object after it has been assigned to. And when the function returns, the local
variable will be destroyed.
In the main function, we create a couple of objects and call the copy constructor and the assignment
operator.
So we have these two objects. Then we call the copy constructor. Then we call the assignment operator.
"a" is going to be "this" inside the assignment operator, and "c" is going to be the argument.
In here.
Then we make a copy of "c".
Then we swap the data between "a" and the copy of "c", and then we return the modified version of "a".
And the copy of "c", which has "a"'s old data, is now destroyed.
So when we call the assignment operator, that calls the copy constructor, to make a copy of "c". Then we
call swap() and then the destructor is called.
So that is the old address of "a" that gets released. And then when we return, "a" has a new memory allocation.
So that is the "copy and swap" idiom.
The advantages of this are, that it is easy to work with.
You do not need to check for self-assignment, because "this" and "temp" must be distinct objects, so they cannot
interfere with each other.
We are re-using code from the copy constructor and the destructor, instead of replicating that code in
the function body.
The code is much shorter, which means there are less things for us to get wrong.
And in the traditional implementation, there are quite a lot of things to get wrong!
The disadvantages are: this always allocates memory. With the traditional implementation, you can check
the size, and you only need to reallocate if the existing buffer is too small.
If the current buffer is large enough, you can just re-use it.
So that is an optimization which you cannot do with copy and swap.
The other disadvantage is that this creates an extra object, so it can use more memory than the traditional
assignment
operator.
In terms of exception safety, copy and swap provides the strong exception guarantee, and you do not
need to do very much work to get it!
If an exception occurs while initializing the new object, we do not do the swap.
Instead, we destroy the new object, the local object. And the original object is left unmodified.
The program is in the same state as when the assignment operation began.
Okay, so that is it for this feature.
I will see you next time, but until then, keep coding!