swap
in Assignment OperatorsClasses that define swap
often use swap
to define their assignment operator. These operators use a technique known as copy and swap. This technique swaps the left-hand operand with a copy of the right-hand operand:
// note rhs is passed by value, which means the HasPtr copy constructor
// copies the string in the right-hand operand into rhs
HasPtr& HasPtr::operator=(HasPtr rhs)
{
// swap the contents of the left-hand operand with the local variable rhs
swap(*this, rhs); // rhs now points to the memory this object had used
return *this; // rhs is destroyed, which deletes the pointer in rhs
}
In this version of the assignment operator, the parameter is not a reference. Instead, we pass the right-hand operand by value. Thus, rhs
is a copy of the right-hand operand. Copying a HasPtr
allocates a new copy of that object’s string
.
In the body of the assignment operator, we call swap
, which swaps the data members of rhs
with those in *this
. This call puts the pointer that had been in the left-hand operand into rhs
, and puts the pointer that was in rhs
into *this
. Thus, after the swap
, the pointer member in *this
points to the newly allocated string
that is a copy of the right-hand operand.
When the assignment operator finishes, rhs
is destroyed and the HasPtr
destructor is run. That destructor delete
s the memory to which rhs
now points, thus freeing the memory to which the left-hand operand had pointed.
The interesting thing about this technique is that it automatically handles self assignment and is automatically exception safe. By copying the right-hand operand before changing the left-hand operand, it handles self assignment in the same was as we did in our original assignment operator (§ 13.2.1, p. 512). It manages exception safety in the same way as the original definition as well. The only code that might throw is the new
expression inside the copy constructor. If an exception occurs, it will happen before we have changed the left-hand operand.
Assignment operators that use copy and swap are automatically exception safe and correctly handle self-assignment.
Exercise 13.29: Explain why the calls to swap
inside swap(HasPtr&, HasPtr&)
do not cause a recursion loop.
Exercise 13.30: Write and test a swap
function for your valuelike version of HasPtr
. Give your swap
a print statement that notes when it is executed.
Exercise 13.31: Give your class a <
operator and define a vector
of HasPtr
s. Give that vector
some elements and then sort
the vector
. Note when swap
is called.
Exercise 13.32: Would the pointerlike version of HasPtr
benefit from defining a swap
function? If so, what is the benefit? If not, why not?