Coding Memo

값 범주 (value categories) (rvalue, lvalue, xvalue) 본문

Language/C++

값 범주 (value categories) (rvalue, lvalue, xvalue)

minttea25 2023. 10. 27. 13:11

C++에는 값을 다음과 같이 분류할 수 있다.

categories of value in C++

 

 

  정의 특징
gvalue generalized lvalue; 변수, 객체, 객체 멤버에 대한 모든 lvalue 표현식; lvalue와 xvalue가 여기에 모두 포함  
prvalue pure rvalue; 일반적인 값으로 객체일 때 소멸자를 호출하지 않아도 되는 값; 어떤 연산자의 피연산자 값을 계산하거나 어떤 객체나 비트 필드를 초기화 할 때 계산되는 값  
xvalue rvalue로 캐스팅 된 lvalue; 리소스를 재사용할 수 있는 개체나 비트 필드; 내부가 expiring 상태로 비어있음 (껍데기만 남아있음) - 내부 데이터가 만료되어 있는 상태일 수 있음
- 왼값을 move로 내부 데이터가 이동하면 xvalue가 됨 (캐스팅)
lvalue 실체를 가지고 있는 객체; 메모리 주소에 접근하는 이름이 있는 비트필드, 함수, 객체; xvalue가 아닌 glvalue - 주소에 접근하는 값이기 때문에 해당 위치에서 값 수정 가능
- &(주소 연산자)로 주소를 취할 수 있음
- 암묵적으로 이동 불가
rvalue 만료중인 값(expiring value); 임시 객체 및 임시 객체의 부분객체, 객체와는 연관되지 않은 값; 메모리 위치에 대해서 식벽자가 아닌 값 자체; - &(주소 연산자)로 주소를 취할 수 없는 객체
- 참조가 아닌 결과를 돌려주는 모든 함수
- 보통 일시적이거나 이동될 것으로 간주되는 값

Note: lvalue는 left의 의미를 크게 가지고 있지 않는다. (lvalue가 상수가 될 수도 있다.) locator value로 이름을 가진 식별자를 의미한다.

Note2: move를 했을 때 만료 된 값 (xvalue)는 적절하게 비워야한다. (이후에 사용할 때 조심해야한다.)

 

 

간단하게 정리하면,

lvalue는 실제로 메모리에 이름을 가지고 존재하는 값이고,

rvalue는 잠깐 사용하거나 곧 사라질 임시 값,

xvalue는 lvalue 였는데, 내부 알맹이를 다른 값에 넘겨주어서 이름만 가지고 있는 껍데기 값이다.


using namespace std;

struct A
{
public:
	int n;
};


int main()
{
	A a; // a is lvalue --- 1

	a.n = 5; // 5 is prvalue, a.n is lvalue --- 2

	A&& b = move(a); // after move, a becomes xvalue --- 3

	A{ 10 }; // <= is prvalue --- 4
	A{ 10 }.n; // <= is xvalue --- 5
}

1. a라는 이름을 가지고 있는 A 타입의 lvalue 이다.

2. 5는 임시로 사용된 비트 필드 값으로 rvalue (prvalue) 이다.

3. move(a)를 통해 a를 b로 데이터를 위임 했다. 이후에 a는 xvalue가 된다.(데이터를 넘겨주었으므로 내용물은 이미 만료되었다고 보면 된다.) 이후에 a 자체를 재사용 할 수는 있겠지만 새로운 값을 얻기 전까지는 바로 사용하면 안된다. 데이터가 망가져있을 수 있기 때문이다.

4.  n에 10을 넣었지만 객체에는 이름도 따로 없고 이후에 사용할 수도 없기 때문에 바로 파괴된다. 즉 rvalue (prvalue)이다.

5. 4번에서의 객체와 마찬가지로 임시 객체를 만들고 이 객체의 맴버(n)을 참조했다. 이 n값은 A{10} 객체가 사라지므로 만료된다. xvalue이다.


forward

 

완벽한 전달(perfect forwarding)을 목적으로 함수에 파라미터를 전달하면서 그 파라미터의 lvalue나 rvalue 특성을 유지하도록 한다.

 

template<typename T>
void foo(T&& arg)
{
	bar(forward<T>(arg));
}

 

1. && (Universal Reference)는 lvalue와 rvalue 모두를 받을 수 있는 템플릿 인수

2. rvalue 함수 파라미터에는 rvalue만 전달할 수 있지만, 함수 내부적으로는 그 파라미터는 하나의 lvalue로 취급된다.

=> 그 파라미터를 다시 다른 함수에 rvalue로 전달하려면 반드시 move나 forward를 적용해야 한다.

 

arg의 lvalue와 rvalue 특성을 그대로 유지하며 bar 함수를 호출한다.

즉, arg가 lvalue 였으면, lvalue의 파라미터로 bar 함수를 호출하고 rvalue 였다면, rvalue의 파라미터로 bar 함수를 호출한다.

 

(forward 관련해서는 사용 예시와 함께 좀 더 봐야 겠다.)


참고 자료

https://devtut.github.io/cpp/value-categories.html#rvalue

 

C++ | Value Categories

Value Category Meanings, rvalue, xvalue, prvalue, lvalue, glvalue

devtut.github.io

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

 

Value Categories: Lvalues and Rvalues (C++)

Learn more about: Lvalues and Rvalues (C++)

learn.microsoft.com

필요한 것만 골라 배우는 모던 C++ - 페터 고칠링 지음, 류광 옮김

'Language > C++' 카테고리의 다른 글

[C++] pack pragma (메모리 정렬)  (0) 2024.03.05
Use After Free  (0) 2023.11.02
Visual Studio glog 사용  (2) 2023.10.26
메타 함수, 템플릿 1  (1) 2023.10.26
STL 반복자와 연산 그리고 <algorithm> 헤더  (1) 2023.10.25