C++에서 l-value(left value)와 r-value(right value)는 변수나 표현식이 메모리에서 차지하는 위치 및 이동 가능성에 따라 구분됩니다.
l-value (좌측 값)
- 메모리에 저장된 값으로, 식의 왼쪽과 오른쪽에서 모두 사용 가능
- 변경 가능하며, 주소를 참조할 수 있음 (& 연산자로 주소를 얻을 수 있음)
- 변수, 참조 변수, 배열 요소, 객체 등이 해당
int x = 10; // 'x'는 l-value (메모리에 저장됨)
x = 20; // 좌항(l-value)인 'x'에 20을 할당 (가능)
int &ref = x; // 참조 가능 (l-value reference)
l-value 특징
- 식의 왼쪽(할당 대상)과 오른쪽(값 제공)에서 모두 사용 가능
- 참조(&)를 통해 l-value reference 생성 가능
r-value (우측 값)
- 임시로 생성되는 값으로, l-value가 될 수 없는 값
- 할당 연산자의 오른쪽에서만 사용 가능
- 값이 있지만 주소를 가지지 않음 (& 연산자로 주소를 얻을 수 없음)
- 리터럴, 연산 결과, 임시 객체 등이 해당
int y = 5; // 'y'는 l-value
y = 10 + 20; // '10 + 20'은 r-value (연산 결과)
int &&r = 10; // r-value reference (C++11부터 가능)
r-value 특징
- 메모리에 직접 저장되지 않는 임시 값
- 참조할 수 없지만, r-value reference (&&) 를 통해 참조 가능 (C++11 이상)
l-value와 r-value의 주요 차이점
구분 | l-value | r-value |
메모리 | 저장됨 | 저장되지 않음 (임시값) |
주소 참조 | 가능 (&) | 불가능 (&) |
사용 위치 | 식의 좌/우 모두 가능 | 식의 우측에서만 사용 가능 |
참조 | int &ref = x; 가능 | int &&r = 10; 가능 (C++11) |
r-value reference (&&) (C++11)
C++11부터 r-value reference(&&)가 도입되어, r-value를 참조할 수 있게 되었습니다.
int &&rr = 10; // '10'은 r-value, r-value reference로 참조 가능
std::cout << rr << std::endl; // 10 출력
r-value reference의 주요 용도
- Move Semantics (이동 시멘틱)
- 불필요한 복사를 줄이고, 효율적인 리소스 이동 가능
- Perfect Forwarding (완벽한 전달)
- 템플릿에서 매개변수를 원래 타입 그대로 전달 가능
Move Semantics 예제
#include <iostream>
#include <vector>
class MoveExample {
public:
std::vector<int> data;
MoveExample(std::vector<int>&& d) : data(std::move(d)) { // r-value reference 사용
std::cout << "Move Constructor Called" << std::endl;
}
};
int main() {
std::vector<int> v = {1, 2, 3};
MoveExample obj(std::move(v)); // v의 데이터를 obj로 이동
}
🔹 std::move(v)를 사용하여 불필요한 복사를 방지하고, 리소스를 효율적으로 이동
Perfect Forwarding 예제
#include <iostream>
#include <utility>
void process(int& x) { std::cout << "L-value reference" << std::endl; }
void process(int&& x) { std::cout << "R-value reference" << std::endl; }
template<typename T>
void forward_example(T&& arg) {
process(std::forward<T>(arg));
}
int main() {
int a = 10;
forward_example(a); // L-value reference
forward_example(20); // R-value reference
}
🔹 std::forward<T>(arg)를 사용하여 원래의 타입을 유지하며 전달
Q&A
Q: l-value와 r-value의 차이점은 무엇인가요?
A: l-value는 메모리에 저장된 값으로 참조가 가능하며, 식의 좌/우에서 사용할 수 있습니다. 반면 r-value는 임시 값으로, 주소를 가질 수 없고 식의 우측에서만 사용됩니다.
Q: r-value reference(&&)는 언제 사용하나요?
A: r-value reference는 주로 Move Semantics(이동 시멘틱)과 Perfect Forwarding(완벽한 전달)에서 사용됩니다. 이를 통해 불필요한 복사를 줄이고, 성능을 최적화할 수 있습니다.
Q: std::move는 무엇인가요?
A: std::move는 l-value를 r-value로 변환하는 함수로, 이동 시멘틱을 활용할 때 사용됩니다. 이를 통해 객체의 소유권을 이전하고, 불필요한 복사를 방지할 수 있습니다.
정리
- l-value → 메모리에 저장된 값, 참조 가능, 식의 좌/우 사용 가능
- r-value → 임시 값, 주소 없음, 식의 우측에서만 사용 가능
- r-value reference (&&) → C++11 이후 도입, Move Semantics 활용 가능
이해를 돕기 위해 요약하면,
✅ l-value는 "메모리에 저장된 값"
✅ r-value는 "일시적인 값"
✅ **r-value reference (&&)**는 "임시값을 참조하기 위한 도구"