class Customer {
public:
Customer() = default;
// copy constructor
Customer(const Customer& rhs)
// note that the construction order is the same as the declaration order
// but not the order in initializer list
: values{rhs.values}, name{rhs.name}
{ }
// move constructor
Customer(Customer&& rhs) noexcept
: values{std::move(rhs.values)}, name{std::move(rhs.name)}
{ }
// copy assignment
// Using ref-qualifier to ensure that only lvalue can call assignment
Customer& operator=(const Customer& rhs) &
{
// if all members are STL, checking self-copy is redundant
if (&rhs == this) return *this;
values = rhs.values;
name = rhs.name;
return *this;
}
// Or, using copy-and-swap idiom
Customer& operator=(Customer rhs) &
{
std::swap(*this, rhs);
return *this;
}
// move assignment
// Using ref-qualifier to ensure that only lvalue can call assignment
Customer& operator=(Customer&& rhs) & noexcept
{
if (&rhs == this) return *this;
values = std::move(rhs.values);
name = std::move(rhs.name);
return *this;
}
private:
std::string name;
std::vector<int> values;
};
=delete special move member functions, as this disables both copy and move semantics — move member functions are deleted, and copy member functinos are undeclared.noexcept to avoid falling back to copy. Customer& operator(Customer rhs) &
{
std::swap(*this,rhs);
return *this;
}
class TreeNode {
public:
TreeNode& operator=(TreeNode&& rhs) & noexcept;
private:
std::unique_ptr<TreeNode> left;
std::unique_ptr<TreeNode> right;
int value;
};
Traditionally, we used to release the LHS’s resource and move RHS to LHS:
TreeNode& TreeNode::operator=(TreeNode&& rhs) & noexcept
{
if (&rhs == this) return *this;
// clean up RHS data
left.reset();
right.reset();
// move-assign to RHS
left = std::move(rhs.left);
right = std::move(rhs.right);
value = rhs.value;
return *this;
}
The better way is to adopt two-phase move:
TreeNode& TreeNode::operator=(TreeNode&& rhs) & noexcept
{
if (&rhs == this) return *this;
// back up the child objects
TreeNode new_left = std::move(rhs.left);
TreeNode new_right = std::move(rhs.right);
int new_value = rhs.value;
// clean up RHS
left.reset();
right.reset();
// move-assign to RHS
left = std::move(new_left);
right = std::move(new_right);
value = new_value;
}
noexcept.