interested if I should add a self-assignment check to the beginning of the assignment operator, or should I just copy the contained element into itself?
C++ Core Guidelines recommends not to do a self-assignment check in a user class if all of its members are self-assignment safe:
Enforcement (Simple) Assignment operators should not contain the pattern if (this == &a) return *this;
???
It is for an efficiency reason. Self-assignments are unlikely to happen in practice. They are rare, and so it is better to avoid doing a self-assignment check in every operation. A self-assignment check probably makes the code faster in self-assignment case (very rare) and makes it slower in all other cases (more common).
Imagine you assign a million elements. In every assignment operation a self-assignment check is done. And it is most probably that it is done for nothing because none of the assignments is actually a self-assignment. And so we do a million useless checks.
If we skip doing a self-assignment check then nothing bad happens except that if self-assignment really happens then we do useless self-assignments of all members (that is sometimes slower than doing a single self-assignment check at the beginning of the assignment operator). But if your code does a million self-assignments it is a reason to reconsider your algorithm rather than to perform a self-assignment check in all of the operations.
However, self-assignment check still must be used for classes that are not self-assignment safe by default. The example is std::vector
. The vector, that is being copied into, first has to delete the existing elements. But if the destination vector and source vector is the same object, then by deleting the elements in destination vector we also delete them in the source vector. And so it won't be possible to copy them after deletion. That is why libstdc++ does a self-assignment check for std::vector
(though it is possible to implement std::vector
without self-assignment check).
But it doesn't do it for std::variant
for example. If you copy a variant into itself then the contained value will be copied into itself. See live example. Because copying it into itself is self-assignment safe (provided the contained value is self-assignment safe).
Thus, libstdc++ does a self-assignment check for std::vector
(for providing self-assignment safety), and doesn't for std::variant
(for efficiency).