Yakk 给出了一个非常好的答案(像往常一样并且被赞成),但这次我想添加更多信息。
在过去的五年中,关于自行分配的政策发生了一点变化。我们最近刚刚在LWG 2468中阐明了这种极端情况。实际上,我应该更准确地说:会议之间的一个非正式小组同意解决这个问题,并且很可能在下个月(2016 年 11 月)投票进入 C++1z 工作草案。
问题的要旨是修改MoveAssignable
需求,明确如果移动赋值的目标和源是同一个对象,那么对赋值后对象的值没有要求(除了必须是有效状态)。它进一步阐明,如果这个对象与 std::lib 一起使用,它必须仍然满足算法的要求(例如LessThanComparable
),无论它是移动分配的还是自移动分配的。
所以...
T x, y;
x = std::move(y); // The value of y is unspecified and x == the old y
x = std::move(x); // The value of x is unspecified
但两者x
和y
仍然处于有效状态。没有内存泄漏。没有发生未定义的行为。
这个职位的理由
它仍然是性能。然而,它被认为swap(x, x)
自 C++98 以来一直是合法的,并且确实在野外发生。此外,由于 C++11swap(x, x)
在 上执行自移动赋值x
:
T temp = std::move(x);
x = std::move(x);
x = std::move(temp);
在 C++11 之前,swap(x, x)
是(相当昂贵的)无操作(使用复制而不是移动)。 LWG 2468阐明,对于 C++11 及之后的版本,swap(x, x)
仍然是(不那么昂贵的)无操作(使用移动而不是复制)。
细节:
T temp = std::move(x);
// temp now has the value of the original x, and x's value is unspecified
x = std::move(x);
// x's value is still unspecified
x = std::move(temp);
// x's value now has the value of temp, which is also the original x value
为了完成这个无操作,self-move-assignment onx
可以做任何它想做的事情,只要它x
处于有效状态而不断言或抛出异常。
如果您想为您的类型指定T
self-move-assignment 是无操作的,那很好。std::lib 正是为unique_ptr
.
如果您想为您的类型指定U
self-move-assignment 使其处于有效但未指定的状态,那也可以。std::lib 正是为vector
. 一些实现(我相信VS)会在无操作的情况下进行自我移动分配vector
。其他的则没有(例如 libc++)。