После std::move
вызывается для объекта, почему язык не вызывает ошибку компиляции, если объект используется после?
Это потому, что компилятор не может обнаружить это условие?
Общий принцип в дизайне языка C ++ — «доверяй программисту». Некоторые проблемы, которые я могу придумать, отвергая любое использование объекта после того, как он стал аргументом std::move
,
std::move
в общем случае было бы эквивалентно решению проблемы остановки. (Другими словами, это не может быть сделано.) Вам придется придумать некоторые правила, которые описывают то, что вы подразумеваете под «после», таким образом, который может быть определен статически.std::move
, (Определенный класс может вызвать утверждение, но это будет очень странный дизайн.)Помните, std::move
это не что иное, как приведение к rvalue-ссылке. Само по себе это на самом деле ничего не двигает. Кроме того, язык только утверждает, что перемещенный из объекта находится в допустимом / разрушаемом состоянии, но кроме этого ничего не говорит о его содержании — он может все еще быть нетронутым, это не может быть или (как std::unique_ptr
это может быть определено, чтобы иметь определенный контент (nullptr
)) — все зависит от того, что реализует конструктор перемещения / оператор перемещения-присваивания.
Таким образом, является ли безопасным / допустимым доступ к перемещенному объекту, полностью зависит от конкретного объекта. Чтение std::unique_ptr
после переезда, чтобы увидеть, если это nullptr
отлично подходит, например, для других типов; не так много.
Это то, что называется проблемой «качества реализации»: для хорошего компилятора или цепочки инструментов гораздо больше смысла выдавать предупреждение для потенциально опасной ситуации использования после перемещения, чем для языкового стандарта, чтобы формально запретить его в точно определенном множество ситуаций. В конце концов, некоторые применения после ходов являются законными (например, в случае std::unique_ptr
, который гарантированно будет пустым после перемещения из), в то время как другие неопределенные случаи не могут быть легко обнаружены — определение того, используется ли объект после перемещения, в целом эквивалентно проблеме остановки.
Вы можете использовать clang-tidy, чтобы обнаружить использование после перемещения: https://clang.llvm.org/extra/clang-tidy/checks/misc-use-after-move.html
Это потому, что мы часто хотим использовать объект move-from. Рассмотрим реализацию по умолчанию 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
,
Состояние после перемещения объекта природы определяется разработчиком; в некоторых случаях перемещение объекта может привести к тому, что он будет в идеальном состоянии, в то время как в других объект может оказаться бесполезным (или, что еще хуже, опасным для использования).
Хотя я в некоторой степени согласен — было бы неплохо иметь возможность генерировать предупреждение, по крайней мере, если объект используется потенциально опасным способом после перемещения, я не знаю вариантов для GCC или Clang, чтобы привлечь внимание к этому типу кода запах.
(На самом деле, для бесстрашных, это может послужить хорошей основой, например, для плагин Clang, в самом деле!)