Страницы

Поиск по вопросам

пятница, 5 октября 2018 г.

Можно ли присваивать объекту, который уже был использован в move-семантике?

Предположим, есть код:
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; }

Комментариев нет:

Отправить комментарий