[우선정리]
lvalue | - 이름과 주소가 있음 - 재참조하거나 수정이 가능 |
rvalue | - 일시적인 값 - 이름이 없고 메모리 주소를 갖지 않음(기본적으로) - 수식을 통해 생성되는 값 - 수정할 수 없음 - 재참조할 수 없음 |
모든 C++의 표현식은 두 가지 카테고리로 분류가 가능합니다.
- 어떤 타입을 가지는가
- 어떤 종류의 값을 가지는가
int a = 10;
[좌측값(lvalue)]
위의 코드에서, a는 메모리상에 존재하는 변수입니다. 메모리상에 존재한다는 것은 주소값을 취한다는 것으로, 이렇게 주소값을 취하는 값을 좌측값(lvalue)이라고 합니다. 이 좌측값이라는 개념은 C에서 정착된 개념이지만, C++에서는 굳이 좌측에 존재한다고 좌측값이 되는 것은 아닙니다.
int a = 10; // 왼쪽(Left)에 존재하는 lvalue
int b = a; // 오른쪽(Right)에 존재하는 lvalue
[우측값(rvalue)]
반면 int a = 10;에서 10의 경우에는 주소값을 취할 수 없는 값입니다. 메모리상에 존재할 수도 있는 a와 다르게 표현식에 잠깐 존재할 뿐, 연산이 끝난 뒤에는 사라지는 값입니다. 이렇게 주소를 취할 수 없는 값을 우측값(rvalue)이라고 합니다.
[좌측값 레퍼런스]
C++에서는 레퍼런스 변수를 지원하기 떄문에, 좌측값에 대해 레퍼런스 변수로 주소값을 받을 수 있습니다.
int a = 10;
int& Refa = a;
일반적으로 사용하는 레퍼런스 변수(&가 하나)의 경우 좌측값 레퍼런스라고 합니다.
[우측값 레퍼런스]
하지만 좌측값 레퍼런스와 다르게, 우측값 레퍼런스는 & 연산자 하나로 받을 수 없습니다.
int& RefDigit = 3;
이 값을 받기 위해서는 &&를 활용하거나, const T&를 활용해야합니다.
int&& RefDigit = 3;
const int& RefDigit2 = 3;
std::cout << RefDigit << std::endl;
std::cout << RefDigit2 << std::endl;
그렇다면 &&와 const T&는 무엇을 의미하는 것일까요?
> 임시값
두 종류의 변수에 대해 알아보기 전에, 임시값이 무엇인지 먼저 알아보도록 하겠습니다. 보통 코드에서 rvalue는 다음의 특징을 갖습니다.
- 이름이 없음(3, 5+2)
- 직접 참조할 수 없음
- 표현식이 끝나면 바로 사라짐
- 메모리에 존재는 하지만, 그 메모리가 레지스터나 스택에 임시로 저장되는 것
정리하자면 rvalue는 이름이 없고 금방 사라지는 값이라고 할 수 있습니다.
1. const T&
C++에서는 const T&로 임시값을 안전하게 참조할 수 있습니다. int a = 3;에서, 3이라는 값은 변수처럼 주소를 갖지 않기 때문에 직접 참조할 수 없습니다. 하지만 const T&를 활용하면 예외적으로 우측값을 참조할 수 있게 됩니다.
이것이 가능한 이유는 const라는 제약이 존재하기 때문입니다. 컴파일러는 "이 값을 바꾸지 않겠다"고 보장하는 const 참조에 한하여 임시값을 임시 객체로 생성한 뒤 수명을 연장시켜 줍니다.
void Print(const std::string& _Str)
{
std::cout << _Str << std::endl;
}
printf("Hello"); // 문자열 리터럴 → std::string 임시 객체 → const 참조로 수명 연장
해당 참조 방식은 임시 객체를 읽기 전용으로 참조할 수 있게 해주는 안전한 방법이며, 여러 기능에서도 널리 쓰이는 방법입니다.
2. T&&
C++11 버전 이상부터 도입된 기능으로, const T&와 마찬가지로 우측값 참조를 지원해주는 방법입니다. 하지만 읽기 전용 참조 방식이 아닌, 임시값에 바인딩 후 그 값을 수정할 수 있는 권한도 갖게 해줍니다.
int&& Ref = 10; // OK: rvalue를 rvalue Reference에 바인딩
Ref = 20; // OK: 수정도 가능
해당 특성은 임시 객체를 수정하거나, 자원을 이동(move)시키기 위한 목적으로 설계된 참조 타입입니다. 임시값이라는 것은 금방 소멸될 것이기 때문에, 값을 수정해도 괜찮다는 전제 하에 사용되는 방식입니다.
'C++' 카테고리의 다른 글
[C++] 완벽한 전달(Perfact Forwarding)과 std::forward (0) | 2025.05.16 |
---|---|
[C++] 이동 생성자와 std::move() (0) | 2025.05.16 |
[C++] 복사 생략(Copy Elision) (0) | 2025.05.15 |
[C++] union (0) | 2025.05.14 |
[C++] 클래스 template (0) | 2025.05.13 |