요약

lvalue

  • 단일 표현식 이후에도 없어지지 않고 지속되는 객체
  • 주소가 있는 애들

rvalue

  • 표현식이 종료된 이후에 더 이상 존재하지 않는 임시적인 값
  • 리터럴, 임시변수, 임시객체

들어가기

lvalue: 왼쪽에 있는 값

rvalue: 오른쪽에 있는 값

기존엔 이런 단순한 개념이었다면 C++11 부터 개념이 다시 정의되고,

C++17부터 개념이 완성된다.

구조

모든 C++ 표현식에는 유형이 있고 value 카테고리에 속한다.

value 카테고리는 표현식 평가 중 임시 객체를 생성, 복사, 이동할 때 컴파일러가 따라야하는 규칙의 기초다.

C++17 표현식의 value 카테고리 정의

image

이러면 사실 무슨 말인지 감이 안 잡힌다.

개념을 정의하고 예시를 들어보자.

정의

lvalue

  • 단일 표현식 이후에도 없어지지 않고 지속되는 객체
  • 주소가 있는 애들
  • 변수, const 변수, 배열 요소, lvalue 참조를 반환하는 함수, 비트필드, union과 class 멤버

rvalue

  • 표현식이 종료된 이후에 더 이상 존재하지 않는 임시적인 값
  • 리터럴, 비 참조 유형을 반환하는 함수 호출, 식 평가 중에 생성되지만 컴파일러에서만 액세스할 수 있는 임시객체
  • 즉, 리터럴, 임시변수, 임시객체

예시

#include <iostream>
#include <string>
using namespace std;

int main()
{
	int a = 3;		// 3: 리터럴 rvalue
	const int b = a;	// b: 수정 불가능한 lvalue
	int c = a + b;		// c: lvalue 	// a + b 연산 결과가 rvalue
	int* p;
	*p = a;			// *p: 참조되지 않은 포인터 lvalue

	const char* str = "hi";		// "hi": 임시변수
	cout << string("hello");	// string("hello"): 임시객체

	++a;	// lvalue. 증가된 자신을 리턴
	a++;	// rvalue. 증가된 복사본을 리턴

	&(++a);
	&(a++);	// error. 레퍼런스 연산자는 lvalue를 요구

	((a < 5) ? a : c) = 7;	// 조건 연산자 리턴: lvalue
}

lvalue 참조자, rvalue 참조자

lvalue 참조자

  • int& a = b;

rvalue 참조자

  • int&& a = 10;
#include <iostream>
#include <string>
using namespace std;

int rvalue() { return 10; }

int main()
{
	int lvalue = 10;
	
	int& a = lvalue;
	int& b = rvalue();	// error. int -> int &

	int&& c = lvalue();	// error. int -> int &&
	int&& d = rvalue();
}

rvalue 참조자는 Move Semantics의 구현을 가능하게 하고, 상당한 성능을 향상시킨다.

Move Semantics란 객체의 리소스(동적할당된 메모리 등)를 또 다른 객체로 이동하는 것.

이와 관련해서 별도 포스트에서 정리.


참고

https://docs.microsoft.com/en-us/cpp/cpp/lvalues-and-rvalues-visual-cpp?view=msvc-170

https://effort4137.tistory.com/entry/Lvalue-Rvalue

https://hannom.tistory.com/208


※ 틀리거나 개선할 부분이 있다면 알려주세요.

태그:

카테고리:

업데이트:

댓글남기기