Hello, and welcome to c++. Weekly i'm your host Jason Turner i am available for
contracting on-site training and code reviews. In this episode i am going to discuss the humble
assignment operator in
c++ and
Specifically starting with, what it means in c++11
so if you've ever had any reason to create your own assignment operator you
Probably know that there are two canonical forms of it and they look, like this
This, is known as your?
Copy, assignment operator and move assignment operator and these two forms cover all of the
Different, ways that you might be assigned to
The object that is being assigned to can, be a
non const reference
or a non const rvalue reference and the object being assigned from could be a
non const reference
A const reference, a rvalue reference and if you passed in a
const rvalue reference object than it is going to go, back to this const lvalue
reference version and this is where, we get back into that, why, you cannot move from const
episode that i did a couple of months ago?
Because of the conversions that the compiler lets you do which is why this works and so now
These are the two canonical forms and we have them explicitly defaulted here but
these are certainly not the only two forms that can exist so we've got these two and
technically, we can, swap the const and
Non constness of these two things now the problem is moving from a
const rvalue reference has no meaning so this one can't be
Defaulted but it is a valid form and we can explicitly delete it and the compiler has no problem with that
So that is cool but this is also not all of the forms that exist?
Because if we were so inclined we have?
Reference qualified versions of these so we can, make our rvalue and lvalue reference qualified versions
Now if you're going to do your reference qualifiers you have to do it on all of the overloads you can't leave any out
So, we have to go in and do all of these
and
Now, we see that the compiler can generate for us the
lvalue reference qualified and rvalue reference qualified versions of each of these except for the ones that are assignments on a const r
rvalue reference this is still not technically all of the versions that could exist but, we start to get into a really, weird place
We have all of these versions, which is 8 so far and we can actually make another 8 of them by making
const rvalue and lvalue reference qualified versions
assigning
To, a const object does not have any logical meaning so there is no way for the compiler to generate these versions
For us however that doesn't mean that, we couldn't technically provide our own version if we wanted to so?
These versions it cannot default so we need to delete them if we're going to mention them here
and
Really, you can delete any overload this doesn't mean that there's anything special, about it because it is a
Assignment operator or anything like that
But if you, want to talk about
Assignment operations this is now the full set of assigning from your
own type things that could exist so for the sake of
Organization we're going to have all the things that are possible on top that is 6 different
Operations and all the things that are impossible on the bottom, which is the remaining 10 operations
So you might be wondering
Why, in the world did i just go through all of this and there are a couple of interesting things that, we can, do?
There are some people, who would say
Now let's go ahead and start testing this code
if
You, want to create an object of type s which, is what we've done here and?
Assign it equal to another object of type s this is going to work
We have assigned a value to a temporary, and that's not something that you could
Do with a built-in, temporary like an int so, some people would suggest, that, we should?
Delete our rvalue reference qualified versions here so that this
illogical operation goes away
Before we move on i should point out that this code, no longer compiles and that is correct
That's what, we wanted to do, we wanted to disable this from compilation?
Now another interesting thing, is that because?
We have explicitly deleted our const rvalue reference if we were to have something like our object s
here named lowercase s and we have our object called s two and
We want to do an assignment of s?
Equal to the value of s 2 this should work
That's fine and if we want to do a move assignment that continues to work?
After we include the proper headers?
and
So the works this is what we would expect now if we were to, make this const now
We actually get a build error
And let me show the output here
We get this use of deleted function for the?
rvalue or for the lvalue
Constant thing comment out this code so that we're
Back to something that compiles again, and so if you really wanted to you
could make
a type, that could be some sort of
Temporary that is assignable only from a?
const
rvalue reference thing so this currently
Can't compile and we can actually see right here with our squiggly, which version it is attempting to call and that
We have explicitly deleted it now, we can't default it because, well
We have no way of defaulting at the compiler doesn't know
Anything special meaning, about this but
We could provide our own version and this will now technically compile although we're doing something really
Bad because we're not returning value from a function that returns a value
But it is possible for us to provide this crazy overload so
just there you have it this is all of the possible things that can happen with an assignment from your, own type and
The things that are logical and theological and the things that the compiler can generate for us or cannot generate for us and
Perhaps, maybe you've
Learned a couple of things that you might implement if you, want to constrain the way that your types are used
Be sure to subscribe follow, me on twitter and check out, any of the links below