1. L-value, R-value란?
다시 한 번 부를 수 있으면 Lvalue
한 번만 쓰이고 다시 불릴 수 없으면 Rvalue
std::string S = "abc"; 같은 경우에도
S값은 나중에 다시 부를 수 있기 때문에 Lvalue,
"abc"는 이 명령어에서만 쓰이고 다시는 쓰이지 않기 때문에 Rvalue.
더 자세한 설명은 다른 분들이 잘 정리해 주셨으니 참고할 것.
https://effort4137.tistory.com/entry/Lvalue-Rvalue
Lvalue Rvalue
C++ Lvalue와 Rvalue에 대한 오해 Lvalue와 Rvalue는 보통 Left-value(왼쪽값)과 Right-value(오른쪽값)로 풀어서 씁니다. 이 때문에 대입 연산자(=)를 기준으로 왼쪽에 위치하는 값이 Lvalue이고 오른쪽에 위치하.
effort4137.tistory.com
2. std:move()
: Lvalue를 std::move()를 통해서 Rvalue로 바꿔줄 수 있다.
ex)
int a = 0;
int b = a;
int c = std::move(a);
c는 Lvalue가 되고 오른쪽 파트는 std::move() 명령어를 통해서 Rvalue가 된다.
Rvalue로 바꾸고 나서는 다시 부르지 않을 임시값으로 바뀐다는 것도 기억해야 한다.
3. Lvalue, Rvalue 레퍼런스
& : Lvalue 레퍼런스
&& : Rvalue 레퍼런스
예제)
std::string 의 경우 실제 더 복잡한 모델이지만
설명을 위해 간단한 모델,
스택에 포인터가 저장이 되고 힙 공간에 문자열이 저장되는 간단한 모델로 설명해 보겠다.
1) 이 코드를 바꾸는 방법은 std::move()를 통해서 Lvalue를 Rvalue 로 바꿔주는 방법과, storeByRRef(std::move(a))
2) "abc"를 직접 넣어주는 방법이 있다. storeByRRef("abc")
메모리 뷰
1. storeByValue(a);
1) stack에 있는 string a는 힙 상의 "abc"를 가리키고 있다.
2) storeByValue(a) 함수가 실행되면 std::string을 value로 받았으니, 스택 프레임이 올라오면서 그 위에 string s 객체가 생기며 값 복사를 통해 "abc"가 다시 정의가 되며 s는 이 "abc"를 가리키게 된다.
3) 그 후 함수 안에서 로컬 string인 b에 s를 넣었다. 스택프레임에 같이 올라온 b 파트에 다시 한번 "abc"가 복사가 되면서 b는 다시 복사된 "abc"를 가리키게 된다.
*결국 storeByValue를 실행시키기 위해서 "abc"를 2번이나 복사하게 된다.
2. storeByLRef(a);
1) string a 가 "abc"를 가리키고 있다.
2) 스택 프레임이 올라오게 되고 &s 가 레퍼런스로 들어왔다는 의미는, 값을 복사하는 것이 아닌 a가 가리키는 힙 공간을 그대로 가리키게 되는 것이다.
3) 로컬 스트링 b에 s가 저장 되며 힙 공간이 카피되며 힙 공간이 복사되고 이 복사된 공간을 가리키게 된다.
* storeByLRef를 실행시키기 위해 "abc"를 1번만 복사하게 된다.
3. storeByRRef("abc");
1) "abc"는 힙 공간에 있는데 이를 가리키는 스택 부분이 임시로 있는 것 뿐이고 실제로 존재하는 것이 아니라는 의미다.
2) 함수가 콜 되며 스택 프레임이 올라가고, Rvalue 레퍼런스 &&s 가 오게되고 이 임시 포인터는 "abc"를 가리킴.
3) std::string b = s; 콜 해주게 되면, local string b가 생기며 힙 공간에 "abc"가 복사가 되며 b는 이 복사된 공간을 가리킴.
결국 1번의 복사가 일어나게 된 것인데, 이 명령어가 //wrong 하다고 미리 적어 놓았다.
s를 받았는데 s를 계속적으로 지칭할 수 있기 때문에, 이 순간부터 s는 Lvalue가 된다.
따라서 Lvalue s를 std::move 를 통해서 Rvalue로 바꿔주어야 한다. (Rvalue 레퍼런스에 넣기 위해서!)
바꿔주게 되면 명령어가 실행되는 순간 &&S가 Rvalue로 바뀌는 것을 알고 b는 abc를 가리키게 됨.
*결국 Rvalue는 move를 통해서 copy가 1번도 일어나지 않음.
결론
value보다는 reference가, reference보다는 Rvalue와 std::move를 통해서 실제 0copy를 만들 수 있다.
'모던C++ > Resource move' 카테고리의 다른 글
4. RVO - Return Value Optimization (0) | 2022.07.23 |
---|---|
3. std::move() 이해하기 - resource 최적화, 0 copy (0) | 2022.07.22 |
1. 포인터와 레퍼런스, Pass by Value (0) | 2022.07.17 |