Можно ли вызывать std::move несколько раз?

96
18 марта 2021, 20:40

Корректен ли подобный код?

template <typename smth> int f() {
  smth x;
  smth y = std::move(x);
  smth z = std::move(x); // Снова x, не y
  return y.do_smth();
}
Answer 1

Никакого определенного ответа на этот вопрос уровня language-lawyer нет. Точнее, с точки зрения абстрактного языка С++ ничего необычного в этом коде нет. В языке С++ существуют разные типы ссылок (включая rvalue-ссылки), категории выражений и правила overload resolution. Если приведенный выше код корректен с точки зрения этих правил, то с точки зрения language-lawyer в этом коде все в порядке.

А что тут будет происходить во время выполнения - зависит только от авторов класса smth. Семантика перемещения - это чисто пользовательская концепция, которая всегда определяется только чисто пользовательским кодом, то есть реализацией класса smth. Только от нее будет зависеть "корректность" или "некорректность" этого кода во время выполнения.

Все соглашения и гарантии, используемые при реализации семантики перемещения - это чисто "джентльменские соглашения". Языку С++ эти соглашения не известны и не интересны.

И что вообще имеется в виду под "корректен"?

Если первая инициализация физически выполнила перемещение из x, то x получил какое-то новое "перемещенное" состояние, допускающее как минимум корректную деструкцию x и, по "джентльменским соглашениям", возможность присвоить x новое значение.

Опять же, вы не обязаны соблюдать последнее соглашение: вы можете полностью запретить какое-либо дальнейшее использование объекта вашего класса после перемещения из него. И даже возможность корректной деструкции "перемещенного" объекта - это тоже не столько требование языка, сколько требование здравого смысла и структуры вашего примера.

Допускает ли "перемещенное" состояние x повторное перемещение из x? Что при этом получится в z? Это определяется только реализацией smth. И если реализация такова, что поведение этого кода полностью определено, то формально тут все совершенно корректно.

А устроит ли вас то, что y и z получат разные состояния и можно ли для такого y делать y.do_smth() - это определяют авторы класса smth. Можно ли делать x.do_smth() и z.do_smth() - тоже определяют именно они.

В наиболее безопасном случае для класса smth семантика перемещения может совпадать с семантикой копирования. Тогда этот код будет вести себя так же, как такой же код без std::move.

В другом варианте реализации перемещение из smth может приводить объект в обычное "пустое" состояние, как будто объект только что сконструирован конструктором по умолчанию. Тогда [наверное] объект z тоже получит такое же "пустое" состояние.

Примеров поведения можно привести бесчисленное множество, но это лишь иллюстрирует тот факт, что происходить будет именно то, что реализовали авторы класса smth.

READ ALSO
Недопустимое имя столбца в запросе

Недопустимое имя столбца в запросе

Есть запрос, который содержит кириллические символы(думаю вся проблема в них)

80
Не работает обработчик события KeyDown, C# [дубликат]

Не работает обработчик события KeyDown, C# [дубликат]

Уже задавал такой вопрос, но ответа нет: не обрабатывается событие KeyDownВот сам обработчик:

97
Поиск дочерних объектов в Unity

Поиск дочерних объектов в Unity

Я создаю префабы и для замены их компонентов использую

104
System.Convert.ChangeType для DateTime

System.Convert.ChangeType для DateTime

Есть generic-метод для преобразования типов, для всех типов в принципе он работает адекватно:

111