C++/Modern C++(11, 14, 17, 20)
[C++11] Rvalue references
deulee
2023. 8. 28. 15:54
"Rvalue reference"는 C++11에서 도입된 기능으로 오로지 Rvalue에만 할당될 수 있는 새로운 레퍼런스이다.
이를 선언하는 방법은 다음과 같다.
T&& // where T is non-template type parameter (such as int, or a user-defined type)
그럼 "Rvalue reference"가 어떻게 바인딩되는지 확인해보자.
#include <iostream>
int main(void)
{
int x = 0; // `x` is an lvalue of type `int`
int& xl = x; // `x1` is an lvalue of type `int&`
int&& xr = x; // error -- `x` is an lvalue
int&& xr2 = 0; // `xr2` is an lvalue of type `int&&` -- binds to the rvalue temporary, `0`
void f(int& x) {}
void f(int&& x) {}
f(x); // calls f(int&)
f(xl); // calls f(int&)
f(3); // calls f(int&&)
f(std::move(x)); // calls f(int&&)
f(xr2); // calls f(int&)
f(std::move(xr2)); // calls f(int&&)
return 0;
}
"Rvalue Reference"는 위와 같은 규칙을 가지게 된다.
그럼 다음과 같은 의문점이 생길 수 있다. 왜 `f(xr2)`는 `f(int&)` 함수를 호출하는 것일까? 분명한 것은 `xr2`의 타입이 `int&&`로 선언되었는데 말이다.
우선 Rvalue와 Lvalue의 차이점을 알 필요가 있다.
Rvalue vs Lvalue
Rvalue와 Lvalue는 이름에서도 나오듯이 차이점이 뚜렷한 "값 카테고리"다.
그럼 어떤 부분에서 차이가 있을까?
Lvalue
- lvalue는 "메모리에서 위치를 가지는 변수나 객체"를 나타냄.
- 변수의 이름이나 객체의 이름은 lvalue이다.
- lvalue는 주소를 가지며, 해당 주소를 통해 값을 변경하거나 접근할 수 있다.
- ex) 변수 `x`, 배열 요소 `arr[3]`, 클래스 객체 `obj`
Rvalue
- rvalue는 "메모리에서 위치를 가지지 않는 일시적인 값"을 나타냄.
- 임시적인 값을 나타내거나, 표현식의 결과 값이나 상수 등이 rvalue이다.
- rvalue는 주소를 가지지 않으며, 일반적으로 임시적으로 생성되는 값이다.
- ex: 리터럴 상수 `42`, 표현식 `x + y`, 함수 호출 결과 `getNumber()`
그럼 이제 위의 예제에서 `int&& z = 0`에서 `f(z)`를 호출할 때 `f(int&)`가 호출되는지 설명하도록 하겠다.
앞서 설명했듯이, rvalue는 임시적인 값(메모리에서 위치를 가지지 않는 값)을 의미했다.
하지만 `main` 함수의 scope에서는 "rvalue"의 타입으로 선언된 변수 `z`는 더 이상 임시적인 값이 아니다. 즉, 메모리에서 위치를 가지고 있는 것이다. 이 말은 변수 `z`는 "rvalue"의 타입으로 초기화되었지만 "lvalue"의 속성을 가지게 된다.
그러므로 `f(int&)`가 호출되는 것이다.