C++의 모든 값은 r-value 아니면 l-value 이다.
l-value | 식의 표현이 지속성을 가진다. 우변 좌변 다 사용 가능하다. 메모리상에 저장되어있다. 즉, 메모리상에 어떤값이 저장되어있을 경우에는 거기에 대입을 할 수 있다.!! |
r-value | 지속성을 가지지 않는 임시적인 값들을 말한다. 좌변에만 사용가능 하다. |
그동안 사용해온 레퍼런스 변수는 변수에 별칭을 지정하는것이었다.
이는 &연산자를 사용하여 원본값을 변화시킬 수 있다.
이것이 l-value reference 이다.
<r-value >
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
int c = a * b;
a* b = 42;
int& f(); --> int& 을 리턴하는 함수 (아직 잘 모르는 부분.)
f() = 42; --> f() 는 좌측값
int* p1 = &f(); --> &foo() 를 할 수 있다. l-value이기 떄문에
int f(); { return 5; }-> int형(정수)형을 리턴하는 함수
int j = 0;
j = f(); -->f()는 r-value 이다.
f() = j; -->따라서 이건 불가능 (리턴값을 바꾸진 못한다.)
int* p2 = &foobar(); -->주솟값을 참조하는거도 불가능
|
cs |
메모리상에 어떤 값이 저장되어있을 경우에는 거기에 대입을 할 수 있다. (l-value)
하지만 int f(); { return 5; } 처럼 리턴값이 있는 int형 함수는 l-value가 아니다.
리턴값 자체는 임시객체이고 메모리상에 저장은 되어있지만 우리가 return값을 다른 값으로 바꿀 수 없다.
이는 r-value이기 때문이다.
r-value는 값자체를 수정할 수 없고 대입을 할 수 가 없기 때문에 r-value 인 것이다.
따라서 return을 하는 함수 즉 임시객체는 r-value이다.!!
<클래스를 반환타입으로 가지는 함수>
String getName()
{
String res("hello world");.
return res;
}
<a는 getName의 return값을 받는 변수 a>
void main()
{
a = getName();
}
- 직관적으로 보았을때 getname()에서 a로 한 번의 깊은 복사가 일어 난다고 예상을 할 수 있다.
- 그러나 출력해본 결과 두 번의 깊은 복사가 일어 났다.
- 복사생성자가 호출이 되고, 대입연산자가 호출이 되면서 깊은 복사는 두번 일어 났다.
- getName()은 소멸되면서 return 값을 반환을 한다. 반환과 동시에 함수가 소멸이 되기 떄문에 a로 바로 대입되는 것이 아닌 임시로 다른곳에 저장이 된다. 그러면서 복사생성자가 한번 더 호출이 된다.
- 동적할당이 두번이나 진행되면서 불필요한 메모리들이 낭비 되고 있고 효율이 떨어진다.
- 따라서 이런 깊은 복사의 문제점을 해결하기 위해 얕은 복사를 해주는 방법을 사용한다.
r-value의 참조 형태는 다음과 같다. String &&r = getName()
r은 r-value 만을 참조할 수 있다. l-value는 참조 할 수 없다.
getName() 얘가 리턴하는건 임시객체인 r-value이다.
r value인 getName()은 표현식 이후에 어디에서도 참조할 수 없는 값이고, 변환을 해도 바뀌지 않는다.
그래서 깊은 복사가 아닌 얕은 복사를 해도 안전하다.
'프로그래밍 > C++' 카테고리의 다른 글
[C++]이동시멘틱_2 (0) | 2021.09.22 |
---|---|
[C++]이동시멘틱_1 (0) | 2021.09.21 |
[C++]동적할당 복사생성자(요약정리) (0) | 2021.09.17 |
[C++]포인터 (0) | 2021.09.16 |
[C++]오버로딩 (0) | 2021.09.15 |