Использование объекта после std:: move не приводит к ошибке компиляции

После вызова std::move объекта, почему язык не вызывает ошибку компиляции, если объект используется после?

Это потому, что компилятор не может обнаружить это условие?

Ответ 1

Общий принцип в языке С++ - это "доверять программисту". Некоторые проблемы, о которых я могу думать, отвергая любое использование объекта после того, как он был аргументом для std::move.

  • Чтобы определить, будет ли данное использование после вызова std::move в общем случае эквивалентным решению проблемы остановки. (Другими словами, это не может быть сделано.) Вам придется придумать некоторые правила, которые описывают то, что вы подразумеваете под "после", таким образом, который можно определить статически.
  • В целом, совершенно безопасно назначать объекту, который был аргументом std::move. (Определенный класс может вызвать утверждение, но это будет очень странный дизайн.)
  • Для компилятора сложно определить, будет ли данная функция просто назначать элементы нового класса.

Ответ 2

Помните, что std::move - это не что иное, как приведение к ссылке rvalue. Сам по себе он ничего не движет. Кроме того, на языке указывается только, что перемещенный из объекта находится в действительном/разрушаемом состоянии, но кроме того, что он ничего не говорит о его содержимом, он все еще может быть неповрежденным, он может и не быть (или, например, std::unique_ptr он может быть определенный для определенного содержимого (nullptr)) - все зависит от того, что реализует оператор move/assign-assign-operator.

Таким образом, независимо от того, является ли это безопасным/допустимым для доступа к перемещенному объекту, он целиком зависит от конкретного объекта. Чтение a std::unique_ptr после перемещения, чтобы убедиться, что оно nullptr отлично подходит, например, для других типов; не так много.

Ответ 3

Это то, что называется проблемой "качества реализации": для хорошего компилятора или инструментальной цепочки гораздо важнее выдать предупреждение о потенциально опасной ситуации использования после выхода, чем для языкового стандарта, чтобы официально запретить его в точно определенный набор ситуаций. В конце концов, некоторые из них используют после того, как ходы законны (например, случай std::unique_ptr, который, как считается, будет пустым после перехода из него), тогда как другие случаи, которые undefined, не могут быть легко обнаружены - обнаружение, независимо от того, используется ли объект после его перемещения, эквивалентен проблеме остановки.

Вы можете использовать clang-tidy для обнаружения использования после перемещения: https://clang.llvm.org/extra/clang-tidy/checks/misc-use-after-move.html

Ответ 4

Это связано с тем, что мы часто хотим использовать перемещенный объект. Рассмотрим реализацию по умолчанию std::swap:

template<typename T> 
void swap(T& t1, T& t2)
{
    T temp = std::move(t1);
    t1 = std::move(t2);   // using moved-from t1
    t2 = std::move(temp); // using moved-from t2
}

Вы не хотите, чтобы компилятор предупреждал вас каждый раз, когда вы используете std::swap.

Ответ 5

Характер состояния объектов после перемещения определяется разработчиком; в некоторых случаях перемещение объекта может оставить его в полностью пригодном для использования состоянии, в то время как в других объект может оказаться бесполезным (или, что еще хуже, опасным для использования).

Хотя я в некоторой степени согласен - было бы неплохо иметь возможность генерировать предупреждение, по крайней мере, если объект используется потенциально опасным способом после перемещения, я не знаю ни параметров для GCC или Clang, чтобы привлечь внимание к этому тип кода запах.

(На самом деле, для бесстрашного, это может послужить хорошей основой, например, для плагина Clang !)