Advanced C++

[C++] l-value와 r-value

로파이 2021. 1. 28. 19:05

C++ 언어에서 l-value와 r-value 라 불리는 표현이 있다.

l-value와 r-value는 연산 결과에 따른 대입 연산에서 비롯된다.

 

l-value는 대입 연산에서 왼쪽과 오른쪽 모두 올 수 있는 표현이고

r-value는 대입 연산에서 오른쪽에만 올 수 있는 표현이다.

int a = 23;
int b = 12;

// 둘 다 모두 가능
a = b;
b = a;

// 산술 연산 결과는 r-value
a = 7 * 9; // l-value = r-value
7 * 9 = b; // error

위의 예시에서 7*9는 "연산 결과"로 오른쪽에만 올 수 있는 표현이다.

 

C++에서 둘을 구분할 수 있는 방법은 l-value는 실제로 메모리 상에 존재하는 객체를 가리키는 표현이고

&연산을 통해 주소를 접근할 수 있다. r-value는 l-value가 아닌 모든 나머지로 잠시 생성되고 없어지기 때문에 코드 상에서 실체가 없다.

 

l-value 예시

일반 변수, 포인터 변수, 참조자

int i = 40;
// 일반 변수 i
i = 40;
// 포인터 변수 p
int* p = &i; 
int& foo();
// 참조자를 반환하는 foo()
foo() = 42;
// 참조자도 l-value이므로 주소를 대입할 수 있다.
int* p1 = &foo();

r-value 예시

(*) 레퍼런스 타입이 아닌 값을 반환하는 함수

리티럴 상수

산술 연산 결과

int foobar();
int j = 0;
int result = foobar(); // 함수 결과는 r-value
int *p2 = &foobar() // error, r-value의 주소는 없음
j = 42; // 리터럴 상수는 r-value

(*) 레퍼런스 타입이 아닌 값을 반환하는 함수

반환 값이 존재하는 함수는 대입을 위해 존재하고 식에서 주로 오른쪽에 온다고 보기 때문에 r-value로 보는 것이 바람직하다.

정확히는 함수 반환시 r-value 타입의 return시 생성되고 대입되자마자 소멸되는 임시 객체가 반환된다.

포인터가 반환된다면 r-value 타입의 포인터 "임시" 객체가 반환된다. 

물론 레퍼런스 타입을 반환한다면 l-value가 될 수 있다.

 

참고: thbecker.net/articles/rvalue_references/section_01.html