ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • std::move에 대하여
    분석과탐구 2022. 10. 3. 15:20

    std::move 선언

    std::move의 선언은 다음과 같다.

    https://en.cppreference.com/w/cpp/utility/move

    템플릿 함수 

    std::move는 함수다. 그 선언 모습은 위와 같다. 첫 번째 줄을 보면 템플릿으로 된 것을 볼 수 있다.

    반환형

    함수의 반환형을 보자. constexpr 키워드가 붙어있다. 함수에 붙은 constexpr은 이 함수가 컴파일 타임에 계산될 수도 있으니, 컴파일 타임에 계산할 수 있다면 우선하라는 의미이다. constexpr을 제외한 반환형은 std::remove_reference_t<T>&&이다. 즉, T라는 타입에서 reference를 제거한 것에 &&을 추가한다. &&은 rvalue reference이다. 즉, T라는 타입에서 reference을 제거하고 다시 rvalue reference를 추가하는 것이다.

    함수 이름

     std::move의 함수 이름은 당연히 move이다.

    매개변수

     매개변수는 T&& t이다. 이것은 universal reference이다. universal reference는 무엇인가?

    https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers

    universal reference는 && 연산자를 사용한다. &&연산자는 대체적으로 rvalue reference를 의미한다. 템플릿 함수처럼 타입을 추론해야 하는 상황에서 &&는 universal reference라고 불리며, rvalue reference와 다르다. universal reference는 lvalue, rvalue를 둘 다 받을 수 있다. 

    1차 결론

    정리하자면, std::move는 템플릿 함수이고, 매개변수가 lvalue인지 value인지 상관없이(universal reference) 매개변수를 그대로 rvalue reference로 되돌려준다는 것이다.

    정의

    std::move의 정의는 다음과 같다.

    https://www.foonathan.net/2020/09/move-forward/

    매개 변수로 받은 universal reference T를 std::remove_reference로 reference를 제거한다. 그리고, rvalue reference를 붙여서 반환한다. std::remove_reference란 무엇인가?

    std::remove_reference란?

    std::remove_reference는 다음과 같다.

    https://cplusplus.com/reference/type_traits/remove_reference/

    T라는 lvale reference 또는 rvalue reference 타입에서 reference를 제거하고 T로 만들어주는 것이다. 어떻게 이것이 가능한 것인가.

    std::remove_reference 정의

    std::remove_reference의 구현은 다음과 같다.

    https://en.cppreference.com/w/cpp/types/remove_reference

    remove_reference는 템플릿 구조체이다. 그 내용은 typedef T type;으로 되어있다. 템플릿 특수화를 이용하여 T&, T&&에서 reference를 제거하고 T를 뽑아낼 수 있게 type으로 재정의 하였다. 이게 끝이다.

    std::move의 실제 코드

    더 찾아보니 위와 같은 스타일은 type_trait에서 많이 사용하는 테크닉이라고 한다. default 접근 제어자가 public인 struct를 사용하여 T를 type으로 재정의한다. 이를 바탕으로 템플릿 특수화를 진행한다. 그렇다면, 정말 이 구현을 이용할까? 다음은 kocw 강의에서 발췌한 코드이다.

    http://www.kocw.net/home/cview.do?mty=p&kemId=1323571

     커스텀한 move 함수를 구현하여 std::move를 대체할 수 있었다. 다른 코드는 어떨까? 다음은 libstdc++의 코드이다. 

    https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-api-4.5/a00936_source.html

     

    오...! 두 코드의 원리가 동일한 것을 볼 수 있다. 끝이 보인다. std::move에서 타입에서 reference를 제거하는 방법은 템플릿 특수화를 이용한 타입 재정의인 것이다.

    결론

    정리하자면, std::move는 템플릿 함수이다. 매개변수가 lvalue인지 value인지 상관없이(universal reference) 매개변수를 그대로 rvalue reference로 되돌려준다는 것이다. rvalue reference를 돌려주기 위하여 내부에서 std::remove_reference를 사용하였고, std::remove_reference안에서는 템플릿 특수화와 타입 재정의를 이용하여 타입에서 레퍼런스를 제거할 수 있는 것이다.

    추가 std::move는 rvalue로 캐스팅하는 것인데 왜 이름이 std::move인가?

    결론에 더하여, std::move는 결국 인자를 rvalue로 만들어주는 것이라 할 수 있다. 그런데, 왜 std::move라 지었을까? 바야네스트룹의 C++11 FAQ를 보자.

    move(x) means "you can treat x as an rvalue". Maybe it would have been better if move() had been called rval()
    , but by now move() has been used for years. The move() template function can be written in C++11 (see the "brief introduction") and uses rvalue references.

    std::move보단 rvalue()로 하는게 낫긴한데, std::move로 계속 불려와서 어쩔수없다 정도로 받아들이면 되겠다.

    댓글

Designed by Tistory.