Предположим, есть код:
struct example
{
example() {
ptr = new int(2);
}
example(example&& rhs) {
ptr = rhs.ptr;
rhs.ptr = nullptr;
}
~example() {
delete ptr;
}
int a = 2;
char b = 'a';
int* ptr;
};
int main()
{
example e;
int* a = new int(1);
example move_e = std::move(e);
e = {1,'b', a};
}
Теперь вопрос: корректно ли после перемещения объекта e опять ему присваивать что-либо? Я знаю, что обращаться к полям после перемещения будет undefined behavior, но а если что-то присваивать объекту? Всё вроде законно, и после присваивания его поля снова будет можно использовать как r-value...
Прав ли я?
Ответ
Безусловно можно.
Есть даже пример в черновике Стандарта:
T old_val = std::move(obj);
obj = std::forward(new_val);
return old_val;
Ну и сама выдержка из Стандарта про то, что представляет из себя перемещенный объект:
Objects of types defined in the C++ standard library may be moved from ([class.copy]). Move operations may be explicitly specified or implicitly generated. Unless otherwise specified, such moved-from objects shall be placed in a valid but unspecified state
Т.е. такие объекты находятся в корректном, но неопределенном состоянии. В частности, все функции-члены такого объекта должны отрабатывать корректно, в том числе и оператор =.
Стоит обратить особое внимание, что указанная цитата относится к типам стандартной библиотеки. Для пользовательских классов программист сам задает состояние объекта после перемещения, т.к. сам же и пишет реализацию перемещающих функций.
Ссылка на ответ на enSO.
При этом, чтобы Ваш код был работоспособен, требуется добавить соответствующий конструктор и оператор присваивания (в данном случае подойдет перемещающий):
example(int a, char b, int* ptr) : a(a), b(b), ptr(ptr) {}
example& operator=(example&& o) {
a = o.a; b = o.b; ptr = o.ptr; o.ptr = nullptr; return *this; }
Комментариев нет:
Отправить комментарий