Операция перемещения должна перемещать и оставлять свой источник в допустимом состоянии
Причина
Это общепринятая семантика. После y = std::move(x) значение y должно быть значением, которое было в x, и x должен быть в допустимом состоянии.
Пример
class X { // OK: value semantics
public:
X();
X(X&& a) noexcept; // move X
X& operator=(X&& a) noexcept; // move-assign X
void modify(); // change the value of X
// ...
~X() { delete[] p; }
private:
T* p;
int sz;
};
X::X(X&& a) noexcept
:p{a.p}, sz{a.sz} // steal representation
{
a.p = nullptr; // set to "empty"
a.sz = 0;
}
void use()
{
X x{};
// ...
X y = std::move(x);
x = X{}; // OK
} // OK: x can be destroyed
Примечание
В идеале, перемещённый объект должен быть значением по умолчанию этого типа. Убедитесь в этом, если нет исключительно хорошей причины не делать этого. Однако не все типы имеют значение по умолчанию, и для некоторых типов установка значения по умолчанию может быть дорогостоящей. Стандарт требует только, чтобы перемещённый объект мог быть уничтожен. Часто мы можем легко и дешево добиться большего: стандартная библиотека предполагает, что можно присвоить перемещённому объекту. Всегда оставляйте перемещённый объект в некотором (необходимо указанном) допустимом состоянии.
Примечание
Если нет исключительно сильной причины не делать этого, сделайте x = std::move(y); y = z; работаю с обычной семантикой.
Применение
(Не применимо) Ищите присваивания членам в операции перемещения. Если есть конструктор по умолчанию, сравните эти присваивания с инициализациями в конструкторе по умолчанию.