본문 바로가기

Programming/C++

Lvalue Rvalue

C++ Lvalue와 Rvalue에 대한 오해

Lvalue와 Rvalue는 보통 Left-value(왼쪽값)과 Right-value(오른쪽값)로 풀어서 씁니다. 이 때문에 대입 연산자(=)를 기준으로 왼쪽에 위치하는 값이 Lvalue이고 오른쪽에 위치하는 값이 Rvalue라고 이해하고 계신 분들이 많습니다. 이것은 C 표준에 입각하여 살펴보면 완전히 틀린 얘기는 아니지만(C 표준에서는 대입 연산자(=)를 기준으로 왼쪽과 오른쪽에 모두 사용될 수 있는 값은 Lvalue이고 오른쪽에만 사용될 수 있는 값이 Rvalue라고 정의하고 있습니다) 잘못된 이해이며, C++ 관점에서는 전혀 다른 관점에서 해석할 필요가 있습니다.

 

C++ 표준에서는 더이상 에서 L과 R은 Left와 Right를 의미하지 않습니다. 지금부터는 위에서 언급한 Left, Right의 개념은 모두 잊어버리시고 Lvalue와 Rvalue를 단순히 고유명사로만 기억하시기 바랍니다.

 

 

Lvalue와 Rvalue의 구분

 

C++에서 모든 표현식은 Lvalue 또는 Rvalue 입니다. Lvalue는 단일 표현식 이후에도 없어지지 않고 지속되는 객체입니다. 쉽게 생각해서 이름을 가지는 객체는 Lvalue라고 얘기할 수 있죠. 그러므로 const 타입을 포함한 모든 변수는 Lvalue 입니다. 반면에 Rvalue는 표현식이 종료된 이후에는 더이상 존재하지 않는 임시적인 값입니다. 상수 또는 임시 객체는 Rvalue 라고 얘기할 수 있겠네요. 그럼 이해를 돕기 위해서 예제를 통해 Lvalue와 Rvalue를 구분해 보도록 하겠습니다.

 

#include <iostream>
#include <string>
using namespace std;
int main()
{
    int x = 3;
    const int y = x;
    int z = x + y;
    int* p = &x;


    cout << string("one");

    ++x;
    x++;
}

 

  

Rvalue를 구분하기 쉽게 굵은 밑줄로 표시하였는데 조금 구분이 되시나요? x, y, z, p 등의 이름을 가지는 변수는 모두 Lvalue 이지만 상수값 3, 임시객체 string("one") 은 표현식이 종료되면 더이상 참조할 수 없는 값이기 때문에 Rvalue 입니다. x + y, &x 와 같은 표현식도 마찬가지이죠. 또 한가지 흥미로운 점은 ++x는 Lvalue인 반면에 x++은 RValue라는 점입니다. 둘 다 증가된 값을 리턴하지만 ++x는 증가된 x 자신을 리턴하기 때문에 Lvalue인 반면에 x++은 증가된 복사본을 리턴하기 때문에 Rvalue 이죠. 이렇게해도 Lvalue와 Rvalue가 잘 구분이 안되신다면 좀 더 확실하게 구분하는 방법이 있습니다. 바로 표현식에 주소 연산자 &를 붙여보는 건데요, & 연산자는 Lvalue를 요구하기 때문에 표현식이 Rvalue라면 컴파일 오류가 나게됩니다.

 

&(++x);
&(x++);     // error C2102: '&' requires l-value

 

 

Rvalue 참조자 &&

 

지금까지 C++에서 int& a = b; 형태로 사용하였던 참조자(Reference)는 Lvalue 참조자입니다. C++11 표준에서는 Lvalue 참조자 이외에도 Rvalue를 참조할 수 있는 Rvalue 참조자가 추가되었습니다. 이름에서 어느정도 예상할 수 있듯이 Lvalue 참조자는 Lvalue만 참조할 수 있고 Rvalue 참조자는 Rvalue만 참조할 수 있습니다. Rvalue 참조자는 Visual Studio 2010 이상 버전의 컴파일러에서 사용 가능합니다.

 

int rvalue()
{
    return 10;
}

int main()
{
    int lvalue = 10;

    int& a = lvalue;
    int& b = rvalue();      // error C2440: 'initializing' : cannot convert from 'int' to 'int &'

    int&& c = lvalue;       // error C2440: 'initializing' : cannot convert from 'int' to 'int &&'
    int&& d = rvalue();
}

 

 

위의 예제에서도 Lvalue 참조 타입에 Rvalue를 대입하려고 하거나 Rvalue 참조 타입에 Lvalue를 대입하려고 하면 컴파일 오류가 나는 것을 볼 수 있습니다. 그런데 우리는 여기서 한 가지 의문점을 가지게 됩니다. 도대체 왜 Rvalue 참조자가 필요한 것일까요? 표현식이 종료되면 더이상 존재하지 않는 임시적인 값을 참조해서 무엇을 하려는 것일까요? 다음 강좌에서는 Rvalue 참조자가 어떤식으로 활용되고 사용시 어떤 장점이 있는지 알아보도록 하겠습니다.

 

 

Reference

 

MSDN - Lvalues and Rvalues

MSDN - Rvalue Reference Declarator: &&

Rvalue References: C++0x Features in VC10, Part 2

 

 

원문 링크

 

DevMachine's Blog


출처 : Devpia  

http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNO=20&no=8625&page=1




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

[C++11] Rvalue Reference #2 - Move Semantics  (0) 2013.01.23
에러 핸들링(Error Handling)  (0) 2012.10.24
this pointer  (0) 2012.09.16
error C2065: 'IDD_Main_DIALOG' : 선언되지 않은 식별자입니다.  (0) 2012.07.25
Bitmap File구조  (0) 2009.09.19