所以有两个赋值运算符——复制和移动,例如:
Implementation& operator= (const Implementation & other) noexcept;
Implementation& operator= ( Implementation && other) noexcept;
话虽如此,这个问题(在第一个答案中)表明声明这样的运算符有一定的优势=,即 按价值:
Implementation& operator= ( Implementation other) noexcept;
那些。在这种情况下,我们不能声明一个接受&&? 否则,只会有不确定性。那么,为什么是标准库中使用的第一种技术,但在 boost 中你可以找到:
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
template < typename ValueType >
any& operator= (const ValueType& rhs)
{
any(rhs).swap(*this);
return *this;
}
any& operator= (any rhs)
{
any(rhs).swap(*this);
return *this;
}
#else
any& operator= (const any& rhs)
{
any(rhs).swap(*this);
return *this;
}
any& operator= (any&& rhs) BOOST_NOEXCEPT
{
rhs.swap(*this);
any().swap(rhs);
return *this;
}
#endif
为什么不在第二个预处理器块中进行相同的实现:
any& operator= (any rhs)
{
any(rhs).swap(*this);
return *this;
}
还是为了重置=接受运算符中的值而完成的?&&rvalue
事实是,随着 C++11 的出现和移动语义的出现,可以将我们真正需要一个对象的新副本的情况与我们只想将一个对象移动到另一个对象的情况分开。通过这种分离,复制赋值运算符(或构造函数)可以抛出异常,而移动运算符几乎总是可以在不抛出异常和创建临时对象的情况下实现。因此,随着向 C++ 11 的过渡,上述构造函数将变成次优的,因为 1)它可以抛出异常 2)它总是创建一个临时对象。
开销脚本的示例:
将复制和交换赋值运算符与移动赋值运算符一起使用将不起作用,因为在这种情况下,当分配右值引用时,编译器将无法在它们之间进行选择。