Hello again!
In this video, we are going to look at using special member functions in C++ 11.
As you may have noticed, the rules are a bit more complicated than they were before. Here is a table which
was drawn up by the man who implemented move
semantics.
Let's have a look at that. And no, you are not expected to remember all this! In this video,
I am going to try and give you some more practical guidelines on how to use special member functions.
The first one is the "Rule of Zero".
If your class does not need to implement a destructor, then it probably does not need to implement
the copy operators either.
So in this case you do not need to implement any special member functions at all.
You can just leave the compiler to synthesise them for you, and they will do the right thing.
And for the large majority of classes, this is quite sufficient.
The compiler will also synthesize a default constructor, unless we define any constructor ourselves.
If we have a constructor which takes arguments, sometimes it is useful to have a default constructor
which will initialize the object with sensible values for the members.
We have talked about the "Rule of Three" and the "Rule of Five".
If your class implements a destructor, then it probably needs to implement the copy operators as well,
because the ones that the compiler synthesizes will not do the correct thing.
So they are not going to re-allocate memory or transfer the file handle.
So in that case, you need to implement the destructor and also the copy constructor and copy assignment
operator.
And you'll probably need to implement a constructor, which will allocate the resource.
In that case, the compiler will not synthesize any move operators.
If copying your object involves a lot of work, and you have performance problems because of it,
Then you can also add move operators.
If you do not do that, then the copy operators will be used.
We also talked about a move-only class.
So this is in the situation where you need to declare a destructor, but you do not want to have duplicate
objects managing the same resource.
And in that case, you can make the class move-only.
And we saw how to do that.
We provided the move constructor and the move assignment operator, but not the copy operators.
And in that case, the compiler will synthesize the copy operators as deleted.
Or we can explicitly declare them as deleted ourselves, which is a bit clearer.
And again, we may want to provide a constructor.
It is possible to make an immoveable class.
So this is a class which cannot be moved or copied.
So objects of this class cannot be used as function arguments or returned from functions.
There are some examples of this in the Concurrency Library.
There are objects which will look a mutex when they are created, and then they unlock the mutex when
they are destroyed.
These are designed to be used within a single scope.
So the idea is, when the program goes out of scope, the mutex is automatically unlocked.
So the designers of the Concurrency Library have enforced this scope lifetime, by making it impossible
to pass these to functions or return them from functions.
To make an object immoveable,
We delete the copy operators, and in that case, the compiler
will not synthesize any move operators.
If we try to copy or move the object, that will call the copy operators, and those are deleted, and we will
get a compiler error.
So here is an example.
We have a class with deleted copy operators.
We do not define any move operators. And in this case, the compiler is not going to synthesize any. So
we can create an object of this class.
But if we try to use the copy constructor,
then we get the compiler error about deleted functions.
And we also get that if we try to use the copy constructor. it is also possible, in theory, to make a
class which can be copied, but not moved.
To do that, we declare the move operators as deleted, and in that case the compiler will synthesize
copy constructor and copy assignment operator.
However, even though the move offices are deleted, the compiler can still decide that a move operator
is the best match for a call.
And then you get a compiler error when the function is called.
For example, if you pass an rvalue, you may expect that this will fall back to the copy constructor,
but in fact you get a compile error.
So for that reason, using copy-only classes is not recommended.
So let's try this out.
So we have our copy operators, and we have the move operators declared as deleted.
So if we call the copy constructor,
we can do that. But if we try to pass an rvalue, then it does not fall back to the copy constructor.
It tries to call the move operator, and then we get the compiler error again.
So, copy-only objects are not very useful.
Okay, so that is it for this feature.
I will see you next time.
But meanwhile, keep coding!