C++ std::move 와 std::forward

박동현·2021년 1월 5일
0

C++공부

목록 보기
2/6

너무 햇갈리는 td::move 와 std::forward에 대해 정리하며 공부해보는 시간을 가졌다.

1. std::move

move라는 이름과 달리 이동을 수행하지 않는다. 단지 자신의 인수를 우측값으로 캐스팅한다(무조건). 물론 우측값은 이동의 후보이기 때문에 어떤 객체에 std::move를 적용한다는 것은 컴파일러에게 그 객체가 이동에 적합하다는 점을 말해주는 것에 해당한다. 그런 객체를 다른 함수에 넘겨주되 그 함수가 객체의 우측값 성질을 활용할 수 있도록 넘겨주고 싳은 경우도 생기는데 이를 위해 객체에 묶이는 매개변수를 우측값으로 캐스팅해야하고 std::move가 하는 일이 바로 그것이다.

실제 리턴 값, 캐스팅하는 것을 볼 수 있다.

static_cast<typename std::remove_reference<T>::type&&>(t)

코드 예제

std::string str = "message";
std::vector<std::string> vec;

vec.push_back(str); //  push_back(const T&)가 호출되어 복사 수행
vec.push_back(std::move(str)); //push_back(T&&)가 호출되어 이동 수행

2. std::forward

보편참조(Universal reference)는 이동일 수도 아닐 수도 있다. 따라서 우측값으로 초기화되는 경우에만 우측값으로 캐스팅되어야하고 std::forward가 하는 일이 바로 그것이다.

void func(const Student& stu); 	//좌측값
void func(Student&& stu);	//우측값

func(s); //좌측값 호출
func(std::move(s)); //우측값 호출

위의 경우에서 첫 번째는 좌측값 함수, 두 번째는 우측값 함수가 호출되는 것을 기대한다. 하지만 모든 함수에서 매개변수는 좌측값이다. func2의 경우 형식이 우측값일뿐 실제로 stu는 좌측값이기 때문에 둘다 좌측값 오버로딩 함수를 실행하게된다. 이러한 경우에 전달된 인수가 우측값이면(우측값일때만!) 우측값으로 캐스팅하는 것이 std::forward이다.

template<typename T>
void func(T&& param)
{
	...
 	func2(std:forward<T>(param));
}
Student s;

3. 추가사항

우측값 참조에는 std::move, 보편 참조에는 std::forward를 사용하자

std::move(rhs.s) //move
std::forward<std::string>(rhs.s) //forward

std::move를 아예 사용하지 않고 std::forward로만 전부 처리 할 수도 있다. 하지만 이는 전달하는 것이 우측값이라는 형식 인수(위의<>안의 부분)을 지정하는 번거로움이 있고 실수를 유발할 수 있기 때문에 구별하여 사용하는 것이 좋다.

반환값 최적화(return value optimization, RVO)의 대상이 될 수 있는 지역 객체에는 절대로 std::move나 std::forward를 적용하면안된다.

profile
엔진 프로그래머를 목표로합니다.

0개의 댓글