struct A; //defines operator=(A&& rhs) where it will "steal" the pointers
//of rhs and set the original pointers of rhs to NULL
A&& operator+(A& rhs, A&& lhs)
{
//...code
return std::move(rhs);
}
A&& operator+(A&& rhs, A&&lhs)
{
//...code
return std::move(rhs);
}
int main()
{
A a;
a = (a + A()) + A(); //calls operator=(A&&) with reference bound to a
//...rest of code
}
template <class T>
void
swap(T& x, T& y)
{
// assume &x == &y
T tmp(std::move(x));
// x and y now have a valid but unspecified state
x = std::move(y);
// x and y still have a valid but unspecified state
y = std::move(tmp);
// x and y have the value of tmp, which is the value they had on entry
}
以上工作,只要 x = std::move(x)不崩溃。它可以离开 x在任何有效的,但未指定的状态。
我认为有三种方法可以为 dumb_array编写移动赋值操作符来实现这一点:
dumb_array& operator=(dumb_array&& other)
{
delete [] mArray;
// set *this to a valid state before continuing
mSize = 0;
mArray = nullptr;
// *this is now in a valid state, continue with move assignment
mSize = other.mSize;
mArray = other.mArray;
other.mSize = 0;
other.mArray = nullptr;
return *this;
}
Expression Return type Return value Post-condition
t = rv T& t t is equivalent to the value of rv before the assignment
其中占位符被描述为: “ t[是一个]可修改的 T 类型的左值;”和“ rv是一个 T 类型的右值;”。请注意,这些是对作为标准库模板参数的类型的要求,但是在标准库的其他地方,我注意到每个关于移动分配的要求都与这个类似。
这意味着 a = std::move(a)必须是“安全的”。如果您需要的是一个身份测试(例如 this != &other) ,那么就去做吧,否则您甚至不能将您的对象放入 std::vector!(除非您不使用那些确实需要 MoveAssignable 的成员/操作; 但是不要介意。)请注意,对于前面的示例 a = std::move(a),那么 this == &other将确实保持不变。
Class &Class::operator=( Class &&rhs ) {
//...
return *this;
}
注意,您仍然通过(非 const) 我值引用返回。
对于任何类型的直接分配,标准都不是检查自我分配,而是确保自我分配不会导致崩溃和烧毁。一般来说,没有人显式地执行 x = x或 y = std::move(y)调用,但别名,特别是通过多个函数,可能会导致 a = b或 c = std::move(d)成为自分配。自分配的显式检查,例如 this == &rhs,当为 true 时跳过函数的主要部分,这是确保自分配安全的一种方法。但这是最糟糕的方法之一,因为它优化了一个(希望是)罕见的情况,而对于更常见的情况却是一个反优化(由于分支和可能的缓存丢失)。
class dumb_array
{
//...
void swap(dumb_array& other) noexcept
{
// Just in case we add UDT members later
using std::swap;
// both members are built-in types -> never throw
swap( this->mArray, other.mArray );
swap( this->mSize, other.mSize );
}
dumb_array& operator=(dumb_array&& other) noexcept
{
this->swap( other );
return *this;
}
//...
};
void swap( dumb_array &l, dumb_array &r ) noexcept { l.swap( r ); }