lValue와 rValue , 참조 우선순위

보물창고·2022년 4월 14일
0

lvalue

  • 등호의 왼쪽과 오른쪽 모두 놓일 수 있음.
  • 메모리가 있어서 주소를 가짐.
  • 이름이 있음.
  • 단일 문장을 벗어나 외부에 참조가 가능함.
  • 참조를 리턴하는 함수 : 호출 이후에 대입이 가능함.
  • const 값 : 수정 불가능한 lvalue임.

rvalue

  • 등호의 오른쪽에만 놓일 수 있음.
  • 메모리가 없어서 주소가 없음.
  • 이름이 없음.
  • 단일 문장에서만 사용가능함. : 세미콜론 만나면 사라짐.
  • 값을 리턴하는 함수 : 임시객체, 정수/실수형 리터럴

- 상수는 아님

lvalue 냐 rValue냐?

: 등호를 기준으로 해서 나누는 것이 아니라, 각각의 특징을 고려해서
lvalue인지 rValue인지를 구분하자.

const int는 정체가 뭐냐?

: 상수 변수는 값을 수정할 수는 없지만, 메모리를 가지고 있기 때문에,
lvalue임.

  • 수정불가능한 lValue라고 함.

rValue에 데이터를 넣을 수 없음.

-상수는 메모리가 없음.
: 임시객체인 rvalue에 상수 4를 넣을 수 없다.

Point().Set 함수를 호출해서 내부 데이터 값 변경이 가능함..

problem

  • 1을 값반환하는 func1과 //int x =2 전역객체를 참조 반환하는 func2를 만들자.
  • 메인에서 v1,v2에 선언과 동시에 값을 대입하자.
  • v1에 20을 대입하자.
  • 20에 v2를 대입하자.
  • 포인터 p1에 v1의 주소를 넣자.
  • 포인터 p2에 10의 주소를 넣자.
  • f1에 10을 대입하자.
  • f2에 20을 대입하자.

#include <iostream>
using namespace std;


int func1()
{
	return 1;
}

int& func2()
{
	int x = 2;
	return x;
}

class Object
{
public : 
	Object() { cout << "constr" << endl; }
	Object(const Object& other) { cout << "copy constr" << endl; }
	~Object() { cout << "destru" << endl; }

};

Object& result()
{
	Object a;
	return a;
}
//=> 참조를 반환하는 것이지만, 실행 결과를 확인해보면, 
// Object obj = result(); 여기서 복사본이 생기는 것을 확인할 수 있음 
// 객체의 반환의 경우, 필수적으로 복사를 가지고 옴. : 임시 객체
// rValue는 상수가 아님.

int main()
{
	int a = 5;

	//func1() = 5;
	func2() = 5;

	// 임시객체 ? : 컴파일러에 의해 생성되는 객체로, 
	Object obj = result();

	Object obj2;
	result() = obj2;
    
    cout << "end" << endl;
}

지역 객체를 반환한다는 것은 참조로 반환을 하든 값으로 반환을 하든,
임시객체를 생성함.


전위형과 후위형 연산자

  • 전위형을 만들때 생각할 수 있는 점.
    전위형은 이렇게 가능함. ++(++n);
    그렇다면 함수를 구성할 때, 값반환을 하게된다면, 위의 연산을 불가함.
    왜냐하면 ++n으로 인해 임시객체가 만들어지고
    최종적으로는 ++(임시객체 증가값) 이렇게 연산이 진행되기 때문임.
    --> 이로 인해서 참조 반환하는 함수를 구성해야 함.

이런식으로 함수를 만들어야 함.
int &operator++(int&a)
{
a = a+ 1;
return a;
}


rValue Ref

: Rvalue만 받을 수 있는 참조

  • 참조 2개를 사용함.
  • 상수는 아님.

여기로 가자.
5. 알아야 하는 부분

const Ref vs rvalue Ref차이

  • const Ref 와 rValue Ref모두 rValue를 받을 수 있음.
    • const Ref는 상수성을 가지고 있음.
    • rValue Ref는 상수성을 가지고 있지 않음.

왜 생긴 것일까??

-> 결론은 const 참조의 모호성 때문이 결정적임.

1) const Ref는 lvalue도 받을 수 있고, rValue도 받을 수 있음. 모호하다.
-> rvalue를 받으면 상수성이 추가됨.

2) rvalue Ref는 rvalue만 받을수 있다.
이 때는 const Ref와 달리 상수성이 없다., 수정이 가능하다.

언제 사용할까?

: move와 perfect Forwarding에서 사용함.


💀핵심 : 참조의 종류

1. 일반 참조(lValue)

: 주소가 있는 값들만 가리킬 수 있음.

2. const ref

: rvalue와 lvalue 모두 참조 가능함.

3. rValue ref

: rvalue만 가리킬 수 있음.

4. 참조의 우선순위

  • 1) lvalue의 경우, lvalue Ref > const lValue Ref

  • 2) rValue의 경우, rValue Ref > const rValue Ref

    • 현재 lValue와 rValue가 모두 있어서 lValue와 RValue 함수가 호출됨.

    • const Ref 함수만 남았을 때

5. 알아야 하는 부분

  • rvalur ref 타입의 변수는 lValue이다.

int &&n = 10;

  • 10은 rValue이지만, 변수 n은 메모리가 있기 때문에, lValue에 속함.

    • 그렇다면, 위의 4번. 참조의 우선순위의 코드 예시에서 n을 foo함수의 인자로
      던져보자! 어떤 함수가 호출될것인가?????
  • 결과 : 예상대로 lValue Ref 함수가 호출되는 것을 확인할 수 있음.
    -> 즉 rvalue 변수는 대입 이후에 메모리를 가지고 있는 lvalue type 임.

  • rValue&&로 캐스팅을 하면, rValue Ref 함수가 호출되는 것을 확인할 수 있음.

6. 보편참조가 존재할 경우의 우선순위

  • 내가 궁금해서 테스트 : 240301

: 물론 보편참조가 lValue , Rvalue 다 가져간다는 거는 알겠는데,
내가 직접 lvalue ,const lvalue , 보편 참조 만들면
그래도 보편 참조가 다 먼저 호출될까?

  • 일단은 명시된 lvalue가 우선순위 높음.

  • 템플릿 자체로만 확인해보자.
    : T& 가 보편참조 보다 앞서다는 것을 확인할 수 있음.

  • 이때는 const& 보다 보편참조가 앞섬

  • 결론
    : 어차피 보편참조는 rVAlue와 lValue 모두 받을 수 있고,
    forward 를 통해서 완벽한 전달이 가능하므로, 가능한
    보편참조를 이용해 템플릿 함수 작성하자.

profile
🔥🔥🔥

0개의 댓글