[Modern C++] 오른값(rvalue) 참조
우선 개념적으로 왼값(lvalue)와 오른값(rvalue)가 있다.
lvalue(left value) : 단일식을 넘어서 계속 지속되는 개체
rvalue(right value) : lvalue가 아닌 나머지 값(임시 값, 열거형, 람다, i++ 등)
이렇게만 보면 이해가 안될 텐데 구체적으로 왼값과 오른값이 뭘까?
'='을 기준으로 나누게 값을 나누게 되는데 왼값의 설명을 다시 한번 쓰자면
'단일식을 넘어서 계속 지속되는 개체'이다. 이게 무슨 뜻이냐면 15번 라인에 변수 a를 선언하고 이 라인을 넘어서
계속해서 값을 변경하거나 사용할 수 있는 개체라는 것이다. 이것이 왼값이다. 반대로 = 오른쪽에 있는 정수 3은
해당 라인 이후로는 더이상 지속되지 않는다. 일시적인 임시 값이라는 뜻이다.
클래스를 이용해 실습을 진행해보자.
Hoon 클래스를 만들고 따로 함수를 만들어서 해당 클래스를 받아주는 형식으로 코드를 만들었다.
27번 라인에서 함수에 lvalue를 넘겨주었고 당연히 정상 작동한다.
28번 라인은 Hoon 클래스의 기본 생성자를 바로 넘겨주는 형태이며 rvalue에 해당한다. 에러가 발생했다.
30번 라인은 동일하게 기본 생성자를 넘겨주는 형태이지만 const 참조 타입으로 선언하니 에러가 발생하지 않았다.
const 하나가 붙었다고 오른값을 받아주는 걸 확인할 수 있었다. 그러면 const가 없는 28번 코드는 왜 오른값을
받아줄 수 없을까?
오른값이라는 것 자체가 곧 사라질 임시적인 값이라는 뜻이기 때문에 해당 값을 받아주어서 다른 여러 동작들을
하게 되면 위험 부담이 크다. 그렇기 때문에 const라는 안전장치를 붙여줘야지만 받아줄 수 있는 것이다.
하지만 const로 선언하게 되면 여러 제약이 생긴다.
이미 공부했듯이 const는 읽기 전용으로 만드는 것이다. 수정이 불가능하다. 21번 라인에 함수는 const 참조로
만들었기 때문에 클래스를 받아주고 난 후에 클래스 내부에 있는 값을 수정한다던가 클래스 내부 함수 등을
수정할 수 없게 된다. 이런 문제를 해결할 수 있는 것이 C++11의 오른값 참조이다.
23번 라인에 오른값 참조 코드를 넣어주었다. 오른값 참조를 하겠다고 선언하는 방법은 && 참조 두 개를
붙여서 선언하는 것이다.
34번 코드를 보면 기존에 왼값이었던 hoon 객체를 더 이상 넣어줄 수 없는 것을 확인할 수 있고
반대로 35번 코드를 보면 기존에 오른값이었던 Hoon 클래스의 생성자를 정상적으로 넣어줄 수 있는 것을 볼 수 있다.
오른값 참조는 다른 일반 참조 타입과 마찬가지로 주소를 넘겨준다.
그렇기 때문에 오른값 참조로 받아주고 데이터를 수정하면 원본 데이터가 수정된다.
그렇다면 이 오른값 참조를 굳이 사용하는 이유는 뭘까?
가장 큰 이유는 사용자에게 전달하는 의미가 일반 참조 타입과 다르기 때문이다.
이게 무슨 말이냐 하면
일반 참조 타입의 경우 원본 데이터의 주소를 넘겨주고 해당 원본 데이터를 마음대로 수정하고 사용할 수 있을뿐더러
원본 데이터를 계속 사용한다는 암묵적인 힌트를 주는 것이다.
하지만 오른값 참조의 경우 원본 데이터의 주소를 넘겨주고 원본 데이터를 마음대로 수정하고 사용할 수 있는 것은
동일하나 해당 원본 데이터를 사용하고 난 후에는 더 이상 사용하지 않겠다는 암묵적인 힌트를 사용자에게 주는 것이다.
원본 데이터를 이후에 사용하지 않겠다는 것은 해당 원본 데이터를 받아들인 함수 등에서, 즉 외부에서 마음대로
원본 데이터를 수정하고 사용할 수 있다는 것이기 때문에 여러 이점들이 생긴다.
원본 데이터에 피해를 주지 않기 위해 깊은 복사를 통해 원본 데이터를 안전하게 두고 깊은 복사를 진행한 데이터를
수정하는 방식으로 사용했다면 오른값 참조 같은 경우 원본 데이터를 마음대로 이용해도 되기 때문에 깊은 복사가
아닌 얕은 복사를 진행해서 원본 데이터를 수정하면 된다. 왜냐하면 해당 원본 데이터는 이후에는 사용하지 않을 것
이기 때문이다.
이러한 오른값 참조는 다음과 같이 std::move를 통해 간단하게 사용할 수 있다.
std::move를 사용하게 되면 44번 라인의 코드와 같이 동작하게 된다.
즉 왼값인 hoon1을 오른값 참조로 캐스팅하는 것이다. 오른값 참조는 위에서도 얘기했듯이 원본 데이터를
마음대로 사용해도 되고 이후에는 원본 데이터를 사용하지 않을 것이기 때문에 원본 데이터를 복사했다기보다
이동했다는 개념이라고 생각하면 된다. 그래서 이름이 move이다.
'프로그래밍 언어 공부 > C++' 카테고리의 다른 글
[Modern C++] 람다 표현식 (0) | 2022.07.19 |
---|---|
[Modern C++] 전달 참조 (0) | 2022.07.18 |
[Modern C++] override, final (0) | 2022.07.15 |
[Modern C++] nullptr (0) | 2022.07.15 |
[Modern C++] 중괄호 초기화 { } (0) | 2022.07.14 |