C++ - L-Value vs R-Value
C++에선, 값을 2개로 분류하고 있다.
바로, L-Value와 R-Value이다.
L-Value와 R-Value가 무엇인지 알아보자.
L-Value
L-Value와 R-Value를 보면, 이름에서 가장 쉽게 연상하는 것은 left와 Right이다. 실제로, L-Value, R-Value의 개념과도 연관이 있기 때문에 L-Value는 식에서 좌측에 있는 값, R-Value는 식에서 우측에 있는 값이라고 설명하는 경우가 많다.
하지만 이는 틀린 설명이다.
왜냐하면, R-Value는 우측에만 있는 것이 맞지만 L-Value는 우측에도 있을 수 있고 좌측에도 있을 수 있기 때문이다.
L-Value란, 메인 메모리에 할당된 공간에 저장되어 있는 값이다.
메모리에 실제로 할당이 되어 있기 때문에, 주소값을 참조하여 사용할 수 있다.
또한, L-Value는 읽는 연산과 쓰는 연산이 모두 가능하다. (값을 변경하는 것이 가능하다.)
R-Value
R-Value는 식에서 우측에만 존재할 수 있다.
R-Value는 잠깐 생겼다가 사라지는 임시 값이다. 그렇기 때문에, 별도의 주소값이 존재하지 않고 이를 참조할 수가 없다.
(임시 레지스터에 저장된 경우 레지스터의 주소값은 존재하겠지만, 이를 사용자가 참조에 사용할 수는 없다.)
예제
글로만 보면, 이해가 힘들 수 있으므로 예제를 한 번 보자.
int A = 3; // A는 L-Value, 3는 R-Value
위의 코드를 보자. int A = 3; 이라는 구문이 있다.
이 때, A라는 것은 특정 메모리 영역에 붙인 이름이다. int A 를 통해, 4바이트의 정수형 값을 저장하기 위한 메모리를 할당하였다. 그리고, 그 안에 최초에 저장되어 있는 쓰레기 값을 밀어내고 초기값을 설정하기 위해, A = 3; 이라는 코드로 저장된 값을 변경하였다
즉, int A = 3; 에서 A는 메모리 공간을 할당받고 있으며, 주소값이 존재하고 그 안에 저장된 값을 바꿀 수 있다는 것이다.
그러므로 A는 L-Value라고 할 수 있다.
int X = 0;
int Y = 1;
int Z = 2;
X = Y + Z;
위의 식에서, X,Y,Z는 모두 L-Value이다. 하지만, 마지막 식에서 (Y + Z)는 R-Value 이다.
두 변수의 값을 합한 값은 메인 메모리에 저장되어 있지 않고, 이를 참조할 수도 없기 때문이다.
3 = 4; //3은 변경될 수 없는 임시의 값이다.
int* A = &3; // 3은 저장된 메모리 공간이 없으므로, 주소값을 참조할 수 없다.
3이라는 값은 잠시 사용될 임시 값이다. 모든 리터럴 숫자가 그렇다. 메인 메모리에 할당된 영역이 없기 때문에 그 값을 바꿀 수가 없다. 또한, 메인 메모리에 할당되지 않았으므로 주소값을 참조할 수 없다.
int Func()
{
int Value = 0;
return Value;
}
int main()
{
int A = 0;
A = Func(); // 가능
Func() = 3; // 불가능
}
Func()는 0이라는 정수 값을 반환하고 있다.
내부에선 L-Value인 Value라는 변수를 반환하고 있지만, 이 변수는 함수가 종료되면 사라진다.
즉, Func()에서 Value를 그 자체로 반환하여도 외부에선 사용할 수가 없는 것이다. (파괴되었으므로)
그렇기 때문에, Func()는 Value를 자체로 반환하지 않고 저장되어 있는 값만 반환한다.
즉, 위의 코드에서 Func()가 반환하는 것은 Value가 아니라 0이라는 R-Value 라고 할 수 있는 것이다.
(임시 값이며, 참조할 수 없는 값)
main함수 내부를 보자.
A = Func(); 라는 코드는 A = 0; 으로 해석할 수 있고, 이는 올바른 문장이다.
반면, Func() = 3; 을 보면, 0 = 3; 이 되므로, 올바른 문장이 아니다.
int Value = 0;
int& Func()
{
return Value;
}
int main()
{
int A = 0;
A = Func(); // 가능
Func() = 3; // 가능
}
위의 함수에선 조금 다르다.
Value는 전역변수이다.
그리고, Func()는 전역변수 Value에 대한 참조를 반환하고 있다.
그러므로, Func()는 Value 자체를 반환한다고 보아도 된다.
그래서 main() 함수 내부의 코드의 의미가 조금 달라진다.
A = Func(); 는 A = Value; 가 되므로, 올바른 문장이다.
여기서 좌측과 우측이 모두 L-Value 이다. 위에서 L-Value는 좌측과 우측에 모두 올 수 있다고 했던 것이 이런 경우이다.
Func() = 3; 이라는 문장은 Value = 3; 이라는 문장으로 해석할 수 있다. 문제가 없는 문장이 된다.