13.52 Explain in detail what happens in the assignments of the HasPtr objects on page 541. In particular, describe step by step what happens to values of hp, hp2, and of the rhs parameter in the HasPtr assignment operator.
rhs parameter is nonreference, which means the parameter is copy initialized. Depending on the type of the argument, copy initialization uses either the copy constructor or the move constructor.
lvalues are copied and rvalues are moved.
Thus, in hp = hp2;, hp2 is an lvalue, copy constructor used to copy hp2. In hp = std::move(hp2);, move constructor moves hp2.
13.53 As a matter of low-level efficiency, the HasPtr assignment operator is not ideal. Explain why. Implement a copy-assignment and move-assignment operator for HasPtr and compare the operations executed in your new move-assignment operator versus the copy-and-swap version.
As the problem suggests, it’s “a matter of low-level efficiency”. When you use HasPtr& operator=(HasPtr rhs) and you write something like hp = std::move(hp2);, ps member is copied twice (the pointer itself not the object to which it points): Once from hp2 to rhs as a result of calling move constructor, and once from rhs to *this as a result of calling swap. But when you use HasPtr& operator=(HasPtr&& rhs), ps is copied just once from rhs to *this.