`std::move`는 객체를 옮기지 않는다. 인자를 rvalue 참조로 캐스트해, 이동 오버로드가 선택되게 할 뿐이다. 실제로 자원을 빼 가는 쪽은 이동 생성자와 이동 대입이다.

C++ 25. 이동과 완벽 전달의 핵심 흐름도
그림. move는 이동 후보로 만들고 forward는 호출자의 값 범주를 보존한다.

move와 forward

template <typename T>
void pass(T&& value) {
    sink(std::forward<T>(value));
}

`T&&`가 템플릿 인자 `T`의 추론과 함께 있을 때만 전달 참조다. 호출자가 lvalue를 넘기면 `T`는 참조로 추론되고, rvalue를 넘기면 값 타입이 된다. `std::forward<T>`는 그 구분을 다음 함수에 보존한다. `std::move`는 항상 이동 후보로 만든다. 전달 참조에 `move`를 쓰면 호출자의 lvalue까지 이동시켜 버린다.

돌려줄 때

지역 객체를 값으로 반환하면 컴파일러가 복사를 생략하거나 이동을 택한다. `return std::move(local);`은 그 생략을 막을 수 있다. 지역 자동 객체의 반환에는 `move`를 붙이지 않는다. 매개변수나 곧 죽을 멤버를 돌려줄 때는 생략이 적용되지 않으므로 `move`가 맞다.

`forward`는 한 번만 쓴다. 두 번 전달하면 두 번째 받는 쪽이 이미 이동된 객체를 볼 수 있다.