Lvalue, Rvalue가 뭘까?
🔸 lvalue
저장할 장소가 있는 값, const가 붙은 값
ex) int a, const char b
🔸 rvalue
임의의 값
ex) 10, 'a'
rvalue와 lvalue가 생긴 이유!?
원래 cpp98까지는 rvalue와 lvalue의 개념이 연산자 오른쪽에 있는 애, 연산자 왼쪽에 있는 애였다.
하지만 deep copy가 꼭 필요하지 않은 경우가 있다.
class A {
std::string a[100000000];
};
A a;
B(a);
B(makestr(a));
위의 코드를 보면 class A는 굉장히 큰 string 배열을 저장하고 있다.
A 클래스를 파라미터로 받는 B의 생성자를 만들 때, 우리는 항상 deep copy로 A 클래스의 string값을 가져오도록 구현했다.
deep copy를 하지 않으면 string 배열을 가르키는 a값을 두 객체가 공유해서 쓰기 때문에 굉장히 위험하다.
하지만 makestr이 A 클래스의 str를 deep copy해서 리턴해주는 함수라면, 코드의 마지막 줄은 deep copy가 2번 일어나게 된다.
크기가 굉장히 큰 배열의 copy를 두 번 하는 것은 오버헤드가 너무 크므로, 별로 좋지 않다.
"그렇다면 다른 곳에서 실제로 사용 중인 값을 매개변수로 넣을 때는 deep copy를 하고, 생성된 임의의 값을 넘겨줄 때는 deep copy를 하지 않으면 어떨까?"라는 생각에서 rvalue와 lvalue의 필요성을 느낄 수 있다.
실제로 사용하고 저장하는 장소가 있는 값은 rvalue이고 이를 매개변수로 넘길 때는 deep copy를 하면 된다.
makestr로 리턴받은 임의의 생성 값은 lvalue이고 이를 매개변수로 넘길 때는 sallow copy를 하면 된다.
코드에서 rvalue와 lvalue를 어떻게 구별할까?
밑의 코드를 보자.
class B {
public:
B(A & a); // lvalue
B(const A & a); // lvalue & rvalue
B(A && a) // rvalue
};
B(A & a) : lvalue 가능
lvalue는 임의의 값이 아니기 때문에 레퍼런스 값으로 보낼 수 있다.
하지만 rvalue는 레퍼런스 값으로 보낼 수 없다.
왜냐하면 매개변수의 값을 바꾸는 a = NULL; 이라는 코드가 있다고 하면 lvalue는 값을 바꾸는 것이 가능하지만, rvalue는 불가능하다.
그래서 해당 함수에는 lvalue만 들어올 수 있다.
B(const A & a) : lvalue, rvalue 가능
위의 생성자 매개변수 (A & a)에 rvalue가 안된다는 문제가 있었다.
하지만 const를 붙이는 순간 rvalue도 들어올 수 있다.
const이기 때문에 값을 바꾸는 경우가 없기 때문이다.
B(A && a) : rvalue 가능
lvalue는 사실상 어떤 함수든 매개변수로 넣는 것이 가능하다.
rvalue값만을 받기 위해 cpp11에서 &&(우측값 레퍼런스)가 생겼다.
&&를 붙이면 rvalue값만을 받게 된다.
'개발 언어 > cpp' 카테고리의 다른 글
CPP explicit 키워드 (0) | 2022.04.27 |
---|---|
CPP 4가지 타입 변환 연산자 (Casting) (0) | 2022.03.20 |
CPP template (0) | 2022.03.18 |
CPP 부모클래스에서 virtual 함수가 하나라도 있으면 소멸자도 무조건 virtual? (0) | 2022.03.10 |
:: Scope Operator(범위 지정 연산자)를 쓰는 3가지 상황 (0) | 2022.02.15 |
댓글