我指的是这个问题: 什么是复制和交换成语?
实际上,上述答案导致以下实现:
class MyClass
{
public:
friend void swap(MyClass & lhs, MyClass & rhs) noexcept;
MyClass() { /* to implement */ };
virtual ~MyClass() { /* to implement */ };
MyClass(const MyClass & rhs) { /* to implement */ }
MyClass(MyClass && rhs) : MyClass() { swap(*this, rhs); }
MyClass & operator=(MyClass rhs) { swap(*this, rhs); return *this; }
};
void swap( MyClass & lhs, MyClass & rhs )
{
using std::swap;
/* to implement */
//swap(rhs.x, lhs.x);
}
但是,请注意,我们可以完全避开 swap(),执行以下操作:
class MyClass
{
public:
MyClass() { /* to implement */ };
virtual ~MyClass() { /* to implement */ };
MyClass(const MyClass & rhs) { /* to implement */ }
MyClass(MyClass && rhs) : MyClass() { *this = std::forward<MyClass>(rhs); }
MyClass & operator=(MyClass rhs)
{
/* put swap code here */
using std::swap;
/* to implement */
//swap(rhs.x, lhs.x);
// :::
return *this;
}
};
请注意,这意味着我们将不再使用 MyClass 在 std::swap 上进行有效的参数相关查找。
简而言之,使用 swap() 方法有什么好处。
编辑:
我意识到在上面的第二个实现中存在一个可怕的错误,这是一个很大的事情,所以我将保持原样以指导遇到这个问题的任何人。
如果运算符 = 定义为
MyClass2 & operator=(MyClass2 rhs)
然后,只要 rhs 是一个 r 值,就会调用移动构造函数。但是,这意味着在使用时:
MyClass2(MyClass2 && rhs)
{
//*this = std::move(rhs);
}
请注意,您最终会递归调用移动构造函数,因为 operator= 调用移动构造函数......
在您遇到运行时堆栈溢出之前,这是非常微妙且难以发现的。
现在解决这个问题的方法是同时拥有
MyClass2 & operator=(const MyClass2 &rhs)
MyClass2 & operator=(MyClass2 && rhs)
这允许我们将复制构造函数定义为
MyClass2(const MyClass2 & rhs)
{
operator=( rhs );
}
MyClass2(MyClass2 && rhs)
{
operator=( std::move(rhs) );
}
请注意,您编写了相同数量的代码,复制构造函数是“免费的”,您只需编写 operator=(&) 而不是复制构造函数和 operator=(&&) 而不是 swap() 方法。