Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

게임 개발 메모장

[ C++ ] L-Value / R-Value 래퍼런스 본문

언리얼 엔진/C++

[ C++ ] L-Value / R-Value 래퍼런스

Dev_Moses 2023. 12. 29. 17:07

C언어에는 lvalue(left value), rvalue(right value) 라는 개념이 존재한다.

 

이 왼쪽 값, 오른쪽 값이란 단어의 의미는 매우 직관적으로 등호 (=) 의 왼쪽에 있으면

lvalue , 오른쪽에 있으면 rvalue 이다.

대입받는 값, 대입되는 값이라고도 할 수 있다.

 

 

lvalue

 

표현식 이후에도 사라지지 않는 값. 이름을 지니는 변수.

 

rvalue

 

표현식 이후에는 사라지는 값. 임시 변수.

 

 

 

 

 

굵은 밑줄이 쳐진 것이 rvalue 이다.

x+y 따위는 실제 변수가 아니라 임시 변수를 생성하여 (레지스터인지 메모리인지)에 저장, 사용한다.

이 값은 일반 변수와 마찬가지로 int 등의 타입을 가지고 있지만

계산이 끝나면 사라지는데 이것이 rvalue 이다.

그리고 명시적으로 선언하여 '이름'을 가지고, 계속 접근할 수 있는 변수가 바로 lvalue 이다.

lvalue에 약간의 연산을 가한 것, 포인터(주소값)등은 따로 저장되어 있는 변수가 아니라

'연산된 결과' 이기에 전부 rvalue 라고 볼 수 있겠다.

함수 리턴 값 따위 또한 rvalue이다.

 

하나 신기했던 것은 ++x 와 x++의 차이인데, x++ 을 쓸 때를 생각해 보면 이렇다.

 

 

위 코드에서, 2번째 줄을 보자.

a는 11로 변경되었지만 b에 대입되는 값은 10이다.

즉 계산식에서 의미하는 a의 값과 계산 후 a가 지니는 값이 다르다.

 

이 계산식의 의미가 'a의 값을 계산에 사용한 다음에' , 'a의 값을 변화시킨다' 인 줄 알았지만 그게 아니었다.

보다 직관적인 방법으로 'a의 값을 카피하여 임시 변수(rvalue)에 저장하고' ,

'원래 a(lvalue)의 값을 변경' , '그리고 임시 변수를 계산에 사용' 이라는 방법이었던 것이다.

 

그렇기 때문에 x++ 과 같은 경우 rvalue, 임시변수이다. x와는 다른 변수인 것. 

 

이렇게 직관적이지 않은 경우를 위한 구분 방법이 있다.

주소값을 가져오는 & 연산자가 있는데,

이 연산자는 이름이 있는 변수인 lvalue의 주소를 가져오는 연산자이다.

그렇기 때문에 &(rvalue)를 쓰면 컴파일 에러가 난다.

 

 

 

 

또한 나는 그다지 자주 사용하지 않았지만 c에는 참조 변수라는 것이 있다.

int& a= b; 와 같이 사용하는 것 말이다.

 

이건 일종의 포인터를 가져와 같은 변수로 사용하는 용법인데

이것 또한 위 &연산자와 마찬가지로 b가 rvalue 이면 에러가 난다.

그 상황을 위해서 c++11에서 새롭게 추가된 참조자가 && 이다. int&& a = 10; 따위로 사용 가능하다.

 

그런데 이게 왜 필요할까? 그걸 위해서는 move semantics 라는 걸 알 필요가 있다.

 

이게 무슨 개념인가 하면, 객체의 리소스(동적 메모리 등)을 다른 객체로 이동하는 것을 말한다.

 

이게 제대로 된 해석인가는 정확하지 않다는 걸 먼저 짚어두고,

내가 이해하기로는 특정 구조체의 값을 다른 구조체로 옮기고자 할 때

각각의 멤버 변수를 전부 copy 하는 게 아니라 포인터 변수를 사용, 가리키는 방식으로 옮기는 것이라고 이해했다.

 

즉 기존의 메모리 위치에 써있는 rvalue를 lvalue가 잡고있는

메모리 위치에 써주는 게 아니라, lvalue가 기존에 rvalue가 잡고 있던 위치를 대신 사용하는 것이다.

메모리 주소공간에 있는 데이터의 변수 이름이 비어있으니(rvalue) 변수 이름을 적어준다(lvalue화)고 봐도 될 것 같다.

 

아무튼 저런 과정을 거침으로 해서 불필요한 연산이 줄어들고, 확실하게 성능이 향상된다고 한다.

그리고 당연하다면 당연하겠지만 lvalue, 이미 이름을 가진 변수는 move semantic을 사용할 수 없다. 

 

 

책을 보다가 본 유의사항으론, rvalue와 lvalue를 쉽게 혼동할 수 있는 경우가 있다고 한다.

int &&a = 10; 에서 a는 rvalue를 가리키지만, 그렇다고 해서 a가 rvalue인 것은 아니다. a는 lvalue이다.

마치 포인터가 특정 구조체를 가리킨다고 해서 구조체가 아니며 4byte void* 타입인 것과 동일하다고 보면 될 것 같다.

 

'언리얼 엔진 > C++' 카테고리의 다른 글

[ C++ ] 게임에서 동기와 비동기 예시  (0) 2024.01.01
[ C++ ] TTuple  (0) 2023.12.30
[ C++ ] 가상 소멸자(Virtual Destructor)  (0) 2023.12.24
[ C++ ] 가상 상속  (0) 2023.12.24
[ C++ ] 가상 함수와 가상 함수 테이블  (0) 2023.12.24