전달참조
전달 참조의 형태는 오른값 참조와 동일하게 &&로 되어 있어 혼동이 될수있다. Template이나 auto와 같은 타입추론/형식연역일 경우 발생하기 때문에 이러한 상황을 보고 구별해야된다.
void Test_RvalueRef(Admin&& admin){}
template<typename T>
void Test_ForwardingRef(T&& param){}
int main()
{
Admin admin;
Test_RvalueRef(std::move(admin));//오른값 캐스팅
Test_ForwardingRef(admin);
Test_ForwardingRef(std::move(admin));
}
위 코드와 같이 &&가 오른값참조만을 지원한다면 왼값을 넣었을때 에러를 내야되지만 템플릿에 적용하게되면 왼값과 오른값 둘다 통과가 되는 현상이 일어난다.
auto&& k2=k1; //왼값참조
auto&& k2=std:move(k1); //오른값 참조
마찬가지로 auto의 경우에도 k1은 왼값이므로 k2가 오른값이라면 move등으로 오른값으로 캐스팅을 하지 않으면 에러를 내야되지만 왼값으로 받아주고 오른값으로 캐스팅을 해주면 오른값으로 받아주는 현상이 일어난다.
※단, const와 같이 추가적인 사항을 넣었을 경우 전달참조가 아닌 오른값 참조로 고정되게 된다.
전달참조의 필요성
이러한 혼동이 있기에 왼값과 오른값을 따로 받아주면 괜찮을 것이라 생각하지만 타입추론의 특성상 다소 어려운점이 있다.
template<typename T,typename T2>
void Test_ForwardingRef(T&& param,T2&& param2)
{
}
위 코드 같은 경우를 생각해보면 왼값과 오른값을 각각 따로 받는다고 가정했을때 동일한 코드가 총4번 반복해야되는 상황이 나온다. 인자가 커지면 커질수록 코드는 기하급수적으로 늘어나기 때문에 전달참조가 필요한 것이다.
std::forward
오른값 참조때에도 말했듯이 오른값 참조타입은 오른값이 아닌 왼값이다. 이것이 문제가 되는 이유는 template에 들어가는 타입은 다음과 같은 형태인 왼값이 되는것이다.
Admin&& a2=std::move(admin);//a2는 오른값참조타입인 왼값이다.
이럴경우 아래와 같은 코드에서 문제가 발생하게 된다.
class Admin
{
Admin(){}
Admin(const Admin&){}//복사생성자
Admin(Admin&&){} //이동생성자
};
int main()
{
Admin admin;
Admin&& ad2=std::move(admin);
Test_ForwardingRef(admin); //복사생성자를 호출하고 싶다.
Test_ForwardingRef(ad2); //이동생성자를 호출하고 싶다.
}
ad2에서 이동생성자를 호출하고 싶었지만,ad2자체는 왼값이기 때문에 복사생성자가 호출되게 된다. 그렇다고 함수자체에서 move를 이용하여 오른값으로 바꾸게 되면 admin같은 왼값마저 오른값으로 바뀌게 된다.
즉, 받은 인자가 왼값참조일때는 왼값을 오른값참조일때는 오른값을 반환해줄 필요가 있다. 아래와 같은 코드가 그 역할을 수행한다.
template<typename T>
void Test_ForwardingRef(T&& param)
{
std::forward(param);//인자가 왼값참조이면 복사생성자를,오른값 참조이면 이동생성자를 호출
}
'C++복습' 카테고리의 다른 글
C++복습) Modern C++/smart pointer (0) | 2022.01.03 |
---|---|
C++복습) Modern C++/lambda (0) | 2021.12.30 |
C++복습) Modern C++/ 오른값 참조( rvalue)와 std::move (0) | 2021.12.29 |
C++복습) Modern C++/ override , final (0) | 2021.12.28 |
C++복습) Modern C++/ Delete (0) | 2021.12.26 |
댓글