[C++] std::move 와 std::forward
언제 std::move를 사용해야 하는지, 언제 std::forward를 사용해야 하는지 알아보는 시간을 가져보도록 하겠습니다.
1. std::move
std::move의 경우 형변환 작업을 수행합니다.
받은 param에 대해 R-value reference를 반환합니다.예를 들면 이런 식 입니다.
#include <iostream>
void Function(int&& Arg)
{
std::cout << "R value Ref!" << std::endl;
}
int main()
{
int i = 0;
Function(i);
//i는 L value입니다.
//컴파일 오류가 납니다.
Function(std::move(i));
//이건 좋습니다.
//std::move 가 R-value 형으로 바꿔서 리턴합니다.
}
하나만 더 해보겠습니다.
#include <iostream>
void Function(int& Arg)
{
std::cout << "L value Ref! " << std::endl;
}
void Function(int&& Arg)
{
std::cout << "R value Ref!" << std::endl;
Function(Arg);
}
int main()
{
int i = 0;
Function(std::move(i));
}
실행 결과는 어떻게 될까요?얼핏보면 무한 재귀처럼 동작할 것 같지만 그렇지 않습니다. 파라미터로 R value Reference를 취한다는 것은호출 당시 넘겨준 형태가 R value Reference 일때 이 함수가 실행되게 하겠다 정도 입니다.파라미터가 함수 내부 취급되는 방식은 어디까지나 지역변수입니다.함수 내부에서의 취급은 별반 달라지지 않습니다.따라서 저렇게 L value Reference로 인식하는 것입니다.
그래서 아래처럼 L value Reference를 받는 함수를 아예 없애면 컴파일이 안됩니다.
#include <iostream>
void Function(int&& Arg)
{
std::cout << "R Value Ref!" << std::endl;
Function(Arg);
//L Value Reference 받는 함수가 없습니다.
//컴파일 에러
}
int main()
{
int i = 0;
Function(std::move(i));
}
이런 상황에서 R value Reference를 인자로 받는 함수를 호출하려면 다시 한번 std::move를 호출 해줍니다.
void Function(int&& Arg)
{
std::cout << "R Value Ref!" << std::endl;
Function(Arg);
//L Value Reference 받는 함수가 없습니다.
//컴파일 에러
Function(std::move(Arg));
//이건 오케이입니다.
//파라미터로 만들어지면서, L Value Ref로 취급되는 Arg를
//다시한번 std::move를 통해 R value Ref 취급하도록 하는 것입니다.
}
2. std::forward
std::forward는 다음과 같은 상황에서 사용합니다.
#include <iostream>
template<class T>
void TemplateFunction(T&& Arg)
{
Function(Arg);
}
int main()
{
int i = 0;
TemplateFunction(i + 3);
//R value Ref를 받으니 전달이 당연히 가능합니다.
TemplateFunction(i);
//템플릿 함수의 경우는 R value reference 인자를 받도록 되어 있어도
//L value 전달이 가능합니다.
}
템플릿 함수의 파라미터가 R value Reference로 되어있다면,
L value Reference 또한 전달할 수 있습니다.
(일반함수는 안됩니다.)
스캇 마이어스가 언급한 universal reference에 의한 타입 붕괴 상황이 바로 이 상황입니다.
템플릿 함수이기 때문에 타입을 컴파일러 마음대로 추론해버리는 상황입니다.
template<class T>
void TemplateFunction(T&& Arg)
{
SomeFunction(std::move(Arg));
}
template<class T>
void TemplateFunction(T&& Arg)
{
SomeFunction(Arg);
}
물론 템플릿 함수 또한 두개로 만들어 버리면 해결이 되기는 합니다만,
그런데 같은 일을 하는 함수를 두개나 만들기가 싫다면, 이때에 std::forward를 사용합니다.
#include <iostream>
void SomeFunction(int&& Arg)
{
std::cout << "R Value Ref!" << std::endl;
}
void SomeFunction(int& Arg)
{
std::cout << "L Value Ref!" << std::endl;
}
template<class T>
void TemplateFunction(T&& Arg)
{
SomeFunction(std::forward<T>(Arg));
}
int main()
{
int i = 0;
TemplateFunction(i + 3);
TemplateFunction(i);
}
std::forward를 사용하니 L value Reference 인자를 위한 함수를 하나 더 만들지 않고도 해결이 가능해 졌습니다.
'C++' 카테고리의 다른 글
[C++] STL Custom Allocator 사용 (0) | 2022.04.08 |
---|---|
[C++] C++ 11 mutable (0) | 2022.03.28 |
[C++] C++11 override, final (0) | 2022.03.28 |
[C++] new[] , delete[] 오버로딩시 주의 사항. (0) | 2022.03.28 |
[C++] const lvalue reference, rvalue reference (2) | 2022.03.23 |
댓글
이 글 공유하기
다른 글
-
[C++] STL Custom Allocator 사용
[C++] STL Custom Allocator 사용
2022.04.08 -
[C++] C++ 11 mutable
[C++] C++ 11 mutable
2022.03.28 -
[C++] C++11 override, final
[C++] C++11 override, final
2022.03.28 -
[C++] new[] , delete[] 오버로딩시 주의 사항.
[C++] new[] , delete[] 오버로딩시 주의 사항.
2022.03.28