프로그래밍 언어/C/C++

[c++11] rvalue reference

소혼 2013. 11. 7. 23:12
반응형

목차로 가기


<개인적으로 공부한 내용들로, 내용이 완벽하지 않을 수 있습니다. 부족한 부분/틀린 부분에 대한 Comment 환영합니다.>



이미 C++  에서는 Reference(참조자)를 지원하고 있습니다.rvalue Reference를 설명하기 전에 기존의 Reference의 예제를 잠깐 살펴보겠습니다.


### c++

#include <iostream>
using namespace std;

int main()
{
    int zero = 0;
    int& a = zero; //OK
    int& b = 0; // Compile Error
    return 0;
}


아시겠지만, Reference에 0을 할당하는 것은 불가능합니다.

예제를 컴파일 해보면 아래와 같은 에러를 볼 수 있습니다. (gcc 기준)

g++ rvalue_reference.cpp
rvalue_reference.cpp: In function ‘int main()’:
rvalue_reference.cpp:8:14: error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’


에러 메시지를 번역해보자면,"int 타입의 rvalue에서 int& 타입인 non-const reference로의  잘못된 초기화" 입니다.

물론 const int& b 로 바꿔도 동작은 합니다.


여기서 핵심은

1. 0은 rvalue입니다.

2. (기존의) reference는 rvalue를 참조하지 못합니다. (const reference(&)는 rvalue도 담을순 있습니다.)


따라서 reference(&)를 lvalue reference라고 부를 수 있습니다. (물론 그동안 이렇게 부를 필요가 없었죠. rvalue reference가 나오기 전까진...)

 


lvalue 와 rvalue


이제 lvalue와 rvalue에 대해 이야기해보겠습니다.

전통적인 의미로 이것은 Left Value와 Right Value를 의미했으나(참조1),

사실상 C에서의 lvalue는 수식의 오른쪽 값이 쓰여질 수 있는 메모리 공간을 가르키는 용어(locater value)입니다.
(오른쪽 값이 rvalue를 의미하는 것은 아닙니다.)


따라서 lvalue는 반드시 left에 올 필요는 없습니다.

### c++

int x = 9;

std::string s;

int* p = 0;

int& ri = x;

x, s, p, ri 모두 lvalue입니다. 4번 라인에서 x는 오른쪽에도 존재합니다.


이제 lvalue를 다시 설명해보고자 합니다.

"lvalue란 이름은 E1 = E2 의 수식에서 E1이 (수정 가능한) lvalue 이어야 한다는 데서 기원하고 있습니다. 그러나 "locaor value"를 의미한다고 생각하는 것이 나을 것입니다."

The name "lvalue" comes originally from the assignment expression E1 = E2, in which the left operand E1 must be a (modifiable) lvalue. It is perhaps better considered as representing an object "locator value."


rvalue는 수식의 값으로써 종종 언급되었습니다.

What is sometimes called ‘‘rvalue’’ is in this International Standard described as the ‘‘value of an expression’’.


rvalue의 대표적인 예는 literal들입니다. 위 예제의 9나 0 또는 'a', "hello"는 rvalue들입니다.


아래의 예를 더 보도록 하겠습니다.

### c++
++i;
i++;

++i는 lvalue이고 i++은 rvalue입니다.


i++이 rvalue인 것을 증명하기 위해, 간단한 테스트를 해보겠습니다.

###c++

int i = 1;
int& a = ++i; // ok
int& b = i++; // compile error

4번 라인은 앞에서 봤던 것과 동일한 에러가 날 것입니다.


앞서 ++i는 lvalue인 i의 값을 증가시킨 후, i를 반환합니다. 따라서 ++i는 lvalue입니다.

반면, i++은 lvalue인 i의 값을 증가시키지만, 증가되기 전의 값을 임시로 보관하여 반환합니다.

따라서, 반환되는 값은 임시로 존재하며 수식이 끝나는 순간 사라지게 됩니다.


또 다른 예를 보겠습니다.

### c++

int i = 1;
const int& p = i;

p = 7; // compile error

p 는 lvalue이지만, const 속성때문에 rvalue인 7을 저장할 수 없습니다.


lvalue나 rvalue 모두 const 나 non-const 속성을 가질 수 있습니다.

### c++

string one("one");
const string two("two");
string three() { return "three"; }
const string four() { return "four"; }

static int s_five = 0;

int& five() { return s_five; }

int main()
{
    one;     // 변경 가능한(non-const)lvalue
    two;     // 변경 불가능한(const) lvalue
    three(); // 변경 가능한(non-const) rvalue
    four();  // 변경 불가능한(const) rvalue

    int& f = five(); // 변경 가능한(non-const)lvalue

    f = 5;

    cout << f << " equals " << s_five << endl;


    return 0;
}


앞에서 보여드린 것처럼 reference는 lvalue를 참조합니다.

따라서 reference를 반환하는 five도 lvalue입니다.


수식(expression)이 끝나도 존재하는 것을 lvalue, 수식의 종료와 함께 사라지는 임시적인 값을 rvalue라고 설명하기도 합니다.

또 다른 설명으로 수식(expression)에서 identity를 가지는 value가 lvalue, identity를 가지지 않는 value가 rvalue라고도 합니다.


여기까지가 C++ 03까지에 대한 내용입니다.


이제 rvalue reference에 대해 설명하도록 하겠습니다.

c++11에서는 rvalue reference(&&)라는 새로운 operator가 등장합니다.

### c++

int&& sum(int a, int b)
{  
    return a + b;
}

int main()
{  
    int&& r = sum(1, 2);
    cout << r << endl;
    return 0;
}

크게 필요성을 느끼기 어려운 예제입니다. 심지어 gcc에서는 warning도 납니다. 하지만 짚고 넘어갈 부분이 있습니다.


보시면 a + b의 결과가 문장(8 line)이 지나갈때까지 살아있게 됩니다.

rvalue인 a + b는 해당 수식이 소멸되는 시점에 사라져야 하지만, rvalue reference로 참조하게 되면 lifetime이 연장되어 존재하게 됩니다.


이러한 value 유형을 xvalue ("eXpiring" value) 라고 합니다.


xvalue는 lvalue처럼 identity를 갖지만 추가로 movability를 갖습니다.

lifetime이 끝나도 identity가 유지되는 한 존재하게 됩니다.


(기존의) lvalue와 xvalue를 묶어서 glvalue("generalized" lvalue) 라고 부릅니다.

glvalue는 identity가 있다는 특징이 있습니다.


기존의 rvalue는 임시적이고 identity를 갖지 않지만, xvalue가 등작했기 때문에 xvalue까지를 포함하여 rvalue라고 합니다.

대신 xvalue가 아닌 rvalue들을 prvalue (pure rvalue) 라고 부릅니다.





rvalue reference의 진정한 가치를 알려면 move semantics에 대해 이해해야 합니다.

move semantics에 대해서는 다음 글에서 이야기하려고 합니다.




참조1 (The main fatures of CPL) : http://comjnl.oxfordjournals.org/content/6/2/134.full.pdf+html

참조 2 : http://blog.smartbear.com/development/c11-tutorial-explaining-the-ever-elusive-lvalues-and-rvalues/

참조 : http://scor7910.tistory.com/66

참조 : http://en.wikipedia.org/wiki/Rvalue_reference#rvalue_reference

참조 : http://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues

참조 : http://stackoverflow.com/questions/371503/why-is-i-considered-an-l-value-but-i-is-not

참조 : http://c0x.coding-guidelines.com/6.3.2.1.html

참조 : https://prog.woong.org/11

반응형

'프로그래밍 언어 > C/C++' 카테고리의 다른 글

[C++11] Range based for loop  (4) 2013.11.13
[C++11] Move semantics  (5) 2013.11.10
[C++11] Variadic template  (0) 2013.11.06
[C++11] unique_ptr  (7) 2013.11.01
[C++11] Type Inference: auto  (4) 2013.11.01