-
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로 계속 불려와서 어쩔수없다 정도로 받아들이면 되겠다.
'분석과탐구' 카테고리의 다른 글
2. express 타입 이해...2 (0) 2023.01.07 1. express 타입 이해...1 (0) 2023.01.07 CRTP는 어떻게 가능할까? (0) 2021.10.13 캐시 친화적인 코드를 찾으려 했으나 실패... (0) 2021.10.12 OverlappedIO에서 소켓 버퍼 사이즈를 바꾸는 것은 대부분 성능에 영향이 없다. (1) 2021.06.05