오른값 참조 (r-value Reference)

Crat3 ㅣ 2023. 10. 11. 17:24

1. 왼값과 오른값

1) 왼값(l-value)

단일식을 넘어 계속 지속되는 값.

주소를 가지는, 메모리에 저장된 값에 접근하는 값.

일반적으로 함수, 변수들이 해당.

 

2) 오른값(r-value)

왼값이 아닌 나머지.

주소를 가지지 않는 임시적인 값, 계산 결과.

 

2. 왼값 참조

데이터를 넘길 때는 복사와 참조의 두가지 방법이 있다.

복사는 데이터를 그대로 복제하여 사용한다. 값을 변경해도 원본의 값이 유지된다.

참조는 데이터의 주소를 포인터의 형태로 넘겨서 사용한다. 값을 변경하면 원본의 값이 변경된다.

void TestKnight_LValueRef(Knight& knight)
{
	knight._hp = 100;
}

// 값을 변경할 수 없도록 하는 왼값 참조
void TestKnight_ConstLValueRef(const Knight& knight)
{
	knight._hp = 100;
}

_hp 멤버 변수를 가지는 knight 클래스의 hp를 변경하는 코드이다.

 

 

3. 오른값 참조

// 오른값 참조
void TestKnight_RValueRef(Knight&& knight)
{
	knight._hp = 100;
}

펫을 가지는 knight 클래스에 대해 생각해보자.

class Knight
{
public:
	Knight() {}
	virtual ~Knight() {}

	Knight(Knight&& knight)
	{
		_hp = knight._hp;
		_pet = knight._pet;
		knight._pet = nullptr;
	}

	void operator=(Knight&& knight) noexcept
	{
		_hp= knight._hp;
		_pet = knight._pet;
		knight._pet = nullptr;
	}

public:
	int _hp = 0;
	Pet* _pet;
};

기존의 l-value 방식으로 복사가 됐다면 Knight의 객체들이 생성되면 한 펫을 모든 객체들이 가리키고 있었을 것이다.

하지만 r-value 방식을 사용하면 임시적으로 사용하는 객체의 데이터를 잘라넣기 / 붙여넣기하여 사용함으로써 위의 문제가 해결이 될 뿐만 아니라 복사가 일어나지 않기 때문에 성능적으로 더 이득을 볼 수 있다.

int main()
{
	Knight k1;
	k1._pet = new Pet;

	// k2 = std::move(k1);
	Knight k2 = static_cast<Knight&&>(k1);
}

std::move 함수를 이용하는 것과 static_cast를 이용하는 방법은 동일하게 작동한다.

'복습' 카테고리의 다른 글

스마트 포인터 - weak_ptr, unique_ptr  (0) 2023.10.13
스마트 포인터 - shared_ptr  (0) 2023.10.11
람다 표현식 (Lambda)  (0) 2023.10.11
함수 객체 ( functor ; 펑터 )  (0) 2023.10.06
함수 포인터  (0) 2023.10.06