
Value Categories
- Value Categories는 연산자 오버로딩, 포인터 등과 같은 C++의 언어적 기능이라기 보다는 컴파일러가 C++의 표현식(Expression)을 이해하고 해석하는 과정 중 한 부분이다.
- Value Categories를 이해하면
- 이해하기 전에는 난해했던 에러 메시지를 효과적으로 해석할 수 있다.
- C++의 언어적 기능인 연산자와 reference가 어떻게 동작하는지에 대한 통찰력을 기를 수 있다.
진화한 LValue와 RValue
초기의 Value Categories에는 C에서 소개되었던 lvalue와 rvalue 두 가지가 있었고, 이들은 비교적 간단명료한 개념들이었다. 하지만 C++과 함께 class, const 그리고 reference가 등장하면서 이러한 기능들에 대응하기 위해 이 개념들은 진화해야했고 복잡해졌다. 얼마 후에 rvalue reference가 추가된 Modern C++이 등장하면서 기존의 개념들은 더욱더 복잡해졌고, 두 가지만 존재하던 Value Categories에 새로운 요소들이 추가되었다.
Object
메모리 상의 정해진 위치에 존재하는 것들을 Object라고 하고 이름을 가지고 있는 오브젝트를 변수(Variable)라 한다. 이 이름은 오브젝트 그 자체인 것처럼 사용된다. 모든 오브젝트가 이름을 가지고 있지는 않다. 이름을 가지고 있지 않은 오브젝트들은 포인터로 관리한다.
/*
* Object: 메모리에 저장된 5
* 변수: x
*/
int x = 5;
/* x를 5인 것처럼 사용한다 */
int y = x + 77;
Lvalues
Lvalue는 메모리에 존재하는 오브젝트의 주소를 참조(Evaluate)할 수 있는 식이다. 예로는 변수(const 변수 포함), 역참조 된 포인터, 배열의 요소, 클래스 멤버와 Lvalue를 반환하는 함수 또는 조건부 연산자(Conditional Operator)가 있다. Lefthand/Left value라고 불리는데 대입 연산자(=)의 왼편에 위치해서 리터럴(Rvalue) 또는 다른 변수에 저장된 값을 대입할 수 있기 때문이다.
/* x는 Lvalue */
int x = 12;
/* 오류! 대입 연산자의 왼편은 항상 Lvalue여야 한다 */
97 = x;
Rvalues
Rvalue는 메모리에 존재하는 오브젝트의 주소를 참조(Evaluate) 하지 않는 식이다. Lvalue가 아닌 것은 Rvalue이다. 예로는 리터럴, 리터럴을 반환하는 식 또는 함수가 있다. Righthand/Right value라고 불리는데 대입 연산자(=)의 오른편에 위치해서 변수 또는 Lvalue를 초기화할 때 사용되기 때문이다.
/* 12는 Rvalue */
int x = 12;
/* (x + 8)은 리터럴을 반환하기 때문에 Rvalue */
int y = x + 8;
L-Value 레퍼런스
L-Value 레퍼런스는 L-Value를 참조한다. & 연산자를 사용한다.
int main()
{
int x = 5;
int& lval_Ref = x;
return 0;
}
R-Value 레퍼런스
R-Value 레퍼런스는 R-Value(임시적인 오브젝트)를 참조한다. && 연산자를 사용한다.
int main()
{
int& x = 100; // *오류* R-Value 100의 L-Value 레퍼런스 x
int&& y = 5; // R-Value 5의 R-Value 레퍼런스 y
int z = 97;
int&& p = z; // *오류* L-Value z의 R-Value 레퍼런스 p
return 0;
}
L-Value 레퍼런스를 매개변수로 하는 함수를 오버로딩하여 R-Value 레퍼런스를 매개변수로 하는 함수를 정의할 수 있다.
#include <iostream>
using namespace std;
// L-Value 레퍼런스를 매개변수로 하는 PrintInt 함수
void PrintInt(const int& x)
{
cout << x << endl;
}
// R-Value 레퍼런스를 매개변수로 하는 PrintInt 함수(오버로딩)
void PrintInt(const int&& x)
{
cout << x << endl;
}
int main()
{
int A = 7;
PrintInt(A);
PrintInt(75);
return 0;
}