게임학원, 게임프로그래머 취업 전문 교육기관 DirectX11/12 자체엔진 게임개발과정,서버프로그래밍,자료구조,알고리즘,유니티,언리얼 게임학원, 언리얼학원 C/C++ 모던) LValue RValue 임시객체 개념파악하기
본문 바로가기

C/C++ 모던) LValue RValue 임시객체 개념파악하기

학생들이 간간히 LValue RValue에 대해서 물어볼 때가 있습니다.

그때마다 기본적으로 C++11 이전과 그 이후로 해서 설명할 필요가 생겼기 때문에 이렇게 정리한 글을 올립니다. 프로그래밍을 공부하는 모든 학생들이 개념을 제대로 잡고 들어갔으면 좋겠습니다.

C++11 이전까지 LValue와 RValue는 이름과 마찬가지로 코드에의 연산 중 왼쪽에 올 수 있는 값과 오른쪽에 존재하는 값으로 구분되어 있었습니다. 이 분류는 현재에서도 통용되는 부분이나 C++11이후 약간은 좀더 추가 설명이 필요하게 되었습니다.

값들을 보면 알겠지만 기본적으로 LValue는 식별자를 가지고 다른 값을 복사 받을 수 있기 때문에 대입이 가능하지만 RValue에 해당하는 값들은 상수거나 따로 식별자가 존재하지 않기 때문에 자신의 상태를 수정할 수가 없습니다.

C++11 이전의 RValue와 LValue는 앞서 설명했던 RightValue와 LeftValue의 약어로서 말그대로 코드식의 왼쪽에 올 수 있는 값들과 오른쪽에 올 수 있는 값의 의미였습니다. C++11 이후로 LValue는 Locaor Value 라는 뜻으로 존재하는 메모리를 식별할 수 있는지도 포함하게 되었고 const의 등장으로 메모리의 위치를 식별할 수 있다고 하더라도 무조건 수정할 수 있는 종류의 LValue만 존재하는 것은 아니게 되었습니다.

메모리의 영역을 가지고 주소도 가지지만 수정 불가능한 LValue 종류는 다음과 같습니다.

1.     배열타입

2.     불완전한 타입(사실 큰 의미는 없습니다 불완전한 타입은 컴파일 오류는 냅니다.)

3.     Const 한정자가 붙은 타입

 다음으로 RValue는 메모리의 위치와 식별자를 특정할 수 없는 데이터들을 의미하는데.

여기에서 3 = Right; 식에 대해서는 쉽게 이해가 갈수 있지만 Left + Right와 Func()에 대해서는 이해가 잘 가지 않을 수가 있으므로 좀더 부연설명을 하겠습니다.

Left + Right의 2개의 int를 연산한 결과를 보통 RValue 혹은 Value of An Expression이라고 부르는데 쉽게 설명해서 식을 계산한 후의 값이라는 뜻입니다.

이때 분명 연산의 결과인 10의 메모리는 분명히 존재하지만 그 메모리의 위치를 알아내야 할 식별자가 존재하지 않습니다. 제가 학생들에게 int와 int 플러스연산을 설명할 때 이 연산을 하기 위해서 필요한 메모리를 8바이트라고 생각하면 안된다고 말하는 것과 같이 int(4) + int(4)를 통해서 나온 결과값 int(4)바이트가 합쳐져 결론적으로는 12바이트를 사용하게 되기 때문입니다.

그렇다면 RValue와 LValue의 구분이 왜 중요하며 C++11이후부터 어째서 이 RValue와 LValue레퍼런스에 대한 세부적인 형 변환 함수와 레퍼런스를 지원하게 되었는지 알아보도록 하겠습니다.

 

일단 LValue레퍼런스는 여러분들이 C++에서 레퍼런스를 처음 접할 때 배우는 녀석으로 일반적으로 레퍼런스라고 부르는 자료형&을 통해서 선언되며 다른 LValue를 통해서 초기화 시켜주지 않으면 사용할 수가 없습니다.

다음으로 RValue레퍼런스는 마치 2중포인터처럼 보이는 녀석으로 자료형&&를 통해서 선언되며 일반적인 LValue레퍼런스에 대입되지 않는 값들을 참조할 수 있습니다.

 

그럼 이런 RValueRef는 도대체 왜 생겨났고 어디서 유용한 것일까요? 모던 C++을 사용하고 깊게 연구하지 않는 유저들은 대체 저것들이 어째서 유용한지에 대해서 일반적으로 알지 못합니다.

이를 제대로 이용하려면 클래스를 통해서 실제 복사와 생성함수들의 실행과정을 통해서 이해하는 것이 좋습니다. 일단 다음의 코드를 보겠습니다.

 

위의 코드의 실행결과까지 보시면 알겠지만 int 할당은 2번 일어나게 되고 그에 따라서 깊은 복사도 2번 일어나게 됩니다.

하지만 잘 생각해본다면 두번째 생성방식인 함수 내부에서 생성된 지역변수를 받아서 생성하는 경우에는 int를 재할당할 이유가 없고 그 int를 새롭게 생성된 객체가 받아서 사용하면 되는 일입니다.

그래서 다음과 같은 RValue 레퍼런스 생성자를 추가합니다.

이에 따라서 만약 자신이 RValue로 생성될 때는 추가적인 생성이 아닌 상대의 int를 그냥 받아서 사용하는 이동생성자를 만들 수 있게 됩니다. 이러한 이동생성자는 클래스가 값형으로 전달될 때 내부에 큰 객체나 동적할당한 객체를 굳이 재할당하지 않고 데이터의 소유권을 이전하는 정도로 처리할 수가 있게 됩니다.

이와 같이 RValue를 기반으로 해서 새로운 모던 C++의 표준으로 std::Move와 std::Foward같은 새로운 인터페이스들이 생겨났고 이를 잘 이용하면 다양하게 인터페이스를 정리하고 최적화에 대한 효율을 높일 수 있게 되었습니다.

다음으로 RValue레퍼런스 이동생성자에도 주의할 점은 있습니다.

다음과 같이 기본자료형에 대한 RValue레퍼런스를 사용했을 경우에는 다음과 같이 모호성이 생기기 때문에 주의해야 합니다.