rValue 참조와 std::move

 

lValue : 단일식을 넘어서 계속 지속되는 개체

rValue : lValue가 아닌 나머지 ( 임시 값, 열거형, 람다 ,i++ 등 )

 

TestKnight_LValueRef(Knight& knight)  : 원본 객체를 넘겨줄테니 수정해도 되고, 맘대로 가지고 놀아도 돼TestKnight_ConstLValueRef(const Knight& knight) : 원본 객체를 넘겨주지만 , 수정은 안돼!

TestKnight_RValueRef(Knight&& knight) : 원본 객체를 넘겨줄테니 수정도 가능하지만, 원본 자체는 이제 더 이상 사용하지 않을거야! ( 이동 대상이 되었다. )

 

rValue를 참조하는 함수.

void TestKnight_RValueRef(Knight&& knight) {
}

 

 

모두의 코드 참고.

MyString str3 = str1 + str2;
위 문장은 아래와 같은 문장이고
MyString str3(str1.operator+(str2));

operator+ 의 정의를 살펴보면 
MyString MyString::operator+(const MyString &s) 으로 우측값을 리턴하고 있는데 이 우측값이 어떻게 좌측값 레퍼런스를 인자로 받는,

MyString(const MyString &str); ( 복사생성자)를 호출 시킬 수 있을까?

& 가 좌측값 레퍼런스를 의미하지만 const 에 한해서만, 예외적으로 우측값도 레퍼런스로 받을 수 있다.

const 레퍼런스 이기 때문에 임시로 존재하는 객체의 값을 참조만 할 뿐 이를 변경할 수 없기 때문에 읽기전용으로 사용하겠구나~ 

str3 생성 시에 임시로 생성된 객체의 string_content 가리키는 문자열의 주소값을 str3 의 string_content 로 해주면 됩니다.
문제는 이렇게 하게 되면, 임시 객체가 소멸 시에 string_content 를 메모리에서 해제하게 되는데, 그렇게 되면 str3 가 가리키고 있던 문자열이 메모리에서 소멸되게 됩니다. 따라서 이를 방지 하기 위해서는, 임시 생성된 객체의 string_content 를 nullptr 로 바꿔주고, 소멸자에서 string_content 가 nullptr 이면 소멸하지 않도록 해주면 됩니다. 매우 간단하지요?
하지만, 이 방법은 기존의 복사 생성자에서 사용할 수 없습니다. 왜냐하면 우리는 인자를 const MyString& 으로 받았기 때문에, 인자의 값을 변경할 수 없게 되지요. 즉 임시 객체의 string_content 값을 수정할 수 없기에 문제가 됩니다. 정확히는 복사생성자 안에서 임시객체의 string_content = nullptr;  할 수 없기 때문에 문제가 된다.

이와 같은 문제가 발생한 이유는 const MyString& 이 좌측값과 우측값 모두 받을 수 있다는 점에서 비롯되었습니다. 그렇다면, 좌측값 말고 우측값만 특이적으로 받을 수 있는 방법은 없을까요? 바로 C++ 11 부터 제공하는 우측값 레퍼런스를 이용하면 됩니다. 

Forward Reference

원래 옛날 이름은 universal reference  였다.

 

전달 참조는 템플릿이나 auto 같이 형식 연역( type deduction) 이 일어나는 곳에서 사용할 수 있다.

 

정확히 모양이 T&& 이여야 한다. 

 

const T&& 이면 이건 더 이상 전달 참조가 아니다.

 

template<typename T>
void Test_ForwardingRef(T&& param)  // 전달 참조
{

}

 

아래 처럼 일반함수에 RvalueRef를 받는 인자는 진짜 말그대로 오른값 참조만 인자로 받는것이다.

lvalue 값이 오면 오류가 뜬다.  

void TestRValueRef(Knight&& k) // 오른값 참조
{

}

 

그런데 Test_forwardingRef 함수에서  T&& param 에서 param은 rvalue  일까 lvalue 일까?

 

lvalue 이다 param 역시 스택 메모리에서 값을 불러 올 수 있는 변수 ( 단일식에서 벗어나면 사용 할수 있는 값) 이기 때문에 param의 타입은 오른값 참조가 맞긴하지만 param 자체는 왼 값 인것이다.

* 오른값 참조 : 오른값만 참조할 수 있는 참조 타입

 

그래서 오른값을 사용하려고 함수 안에서 std::move(param) 해주면 괜찮게 작동하는데 T가 왼값 참조일때도 std::move() 를 해주게 되면은 안된다. 

 

 

결론은 std::forward<T> 와 짝궁이다.

'C++과 언리얼로 만드는 게임 개발 > Part1. C++ 문법' 카테고리의 다른 글

람다(lambda) && 스마트 포인터  (0) 2022.05.02
Day12 ( 82.14% )  (0) 2022.04.20
Day11 ( 80.36% )  (0) 2022.04.17
Day10 ( 79.46% )  (0) 2022.04.17
Day9 ( 71.42% )  (0) 2022.04.04

+ Recent posts