It is commonly known that when implementing an assignment operator one has to protect against self-assignment, at least when the class has non-POD members. Usually it is (or is equivalent to):
Foo& operator=(const Foo& other) { if (&other == this) return *this; ... // Do copy }
What were the reasons for not inserting the self-assignment protection automatically? Are there use cases when self-assignment does something non-trivial and practically useful?
Foo& operator=(const Foo& other) { if (&other == this) { // Do something non-trivial } else { // Do copy } return *this; }
To summarize the answers and discussion by now
Looks like non-trivial self-assignment can never be really useful. The only option proposed was to put an assert
there in order to detect some logical errors. But there are quite legitimate self-assignment cases like a = std::min(a, b)
, so even this option is highly dubious.
But there are two possible implementations of a trivial self-assignment:
&other == this
. Always work, though may have negative performance impact due to an extra branching. But in a user-defined assignment operator the test must be almost always explicitly made.I still don't see why the C++ standard could not guarantee that in a user-defined assignment operator &other != this
. If you want no branching, use the default operator. If you are redefining the operator, some test is needed anyway...
Definition of self-assignment : the act of assigning something (such as a task) to oneself working on/by self-assignment also : the task or work that is assigned Alexander came to Winged Foot in 1959 to shoot the U.S. Open. It was a self-assignment that resulted in a series of iconic photos … —
The general reason to check for self-assignment is because you destroy your own data before copying in the new one. This assignment operator structure is also not strongly exception safe.
Assignment Operators Overloading in C++You can overload the assignment operator (=) just as you can other operators and it can be used to create an object just like the copy constructor. Following example explains how an assignment operator can be overloaded.
Self-assignment protection is only necessary for types where the code being skipped is dangerous when applied to itself. Consider the case where you have a user-provided assignment operator because each individual object has some kind of identifier, which you don't want to copy. Well, you can "copy" the other values just fine in self-assignment cases. So inserting an invisible self-assignment test is just adding a pointless and potentially costly conditional branch.
So it's not about self-assignment being useful; it's about self-assignment not always needing protection.
Furthermore, C++ generally doesn't like adding code like that to your code without you explicitly asking for it. It's typically done in terms of whole functions, not part of functions. Even destructor calls at the end of blocks are something you asked for when you put the object to be destroyed on the stack.
There are algorithms where it can happen.
You know the lhs and rhs might be the same but it is just simpler to do the assignment than check. E.g., consider a = std::min(a,b);
- simpler and perhaps easier to understand than if (a > b) a = b;
- now consider more complicated examples of similar things.
You don't know whether lhs and rhs might be the same, because they may have been passed in from somewhere else.
These algorithms where it can happen are not uncommon.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With