- r-value : modern c++의 꽃이라해도 과언이 아니다
class Knight
{
public:
void Func() {}
void ConstFunc() {}
public:
int _hp = 100;
};
void TestKnight_Copy(Knight knight) { /*Knight를 복사로 받는다*/ }
void TestKnight_LValRef(Knight& knight) { /*Knight를 참조로 받는다*/ }
void TestKnight_ConstLValRef(const Knight& knight) {}
void TestKnight_RValRef(Knight&& knight) { /*Knight를 오른값 참조로 받는다*/ }
int main()
{
Knight k1;
TestKnight_Copy(k1); // Knight가 사이즈가 클 경우 성능의 문제가 발생한다.
TestKnight_LValRef(k1); // 불필요한 복사가 없기에 성능에 유리하다.
TestKnight_LValRef(Knight()); // Error : 단, 임시객체는 받을수 없드
TestKnight_ConstLValRef(Knight()); // Const는 임시객체도 받아진다.
// 임시객체를 const를 붙여서만 받아주는 이유는 생각해보면 당연한데
// 내부에서 수정할 경우 임시객체라서 의미가 없기때문이다.
// 또한 const객체를 받을경우 단점은
/*
void TestKnight_ConstLValRef(const Knight& knight)
{
knight.Func(); // Error : const가 붙은 함수만 호출가능
knight.ConstFunc(); // Okay :
}
*/
TestKnight_RValRef(k1); // l-value는 받지못한다.
TestKnight_RValRef(Knight()); // okay - r-value를 받을수 있다.
// 근데 이걸 왜 써야할까?
// 우선 세 참조의 목적을 알아야한다.
void TestKnight_LValRef(); // 내부수정이 가능하게 해줄께
void TestKnight_ConstLValRef(); // 내부수정은 불가능하지만 읽게는 해줄께
void TestKnight_RValRef(); // 내부수정뿐만 아니라 나는 더이상 사용안할테니 메모리의 이동 권한까지 줄께
}
좀 더 정확한 예시를 보자
class Knight
{
public:
void operator=(const Knight& knight)
{
cout << "operator=(const Knight& knight)" << endl;
_hp = knight._hp;
if(knight._pet)
_pet = new Pet(*knight._pet);
// 복사마다 이런 깊은복사를 해야하는데 복사비용이 상당하다
}
void operator=(Knight&& knight) noexcept
{
cout << "operator=(Knight&&)" << endl;
_hp = knight._hp;
_pet = knight._pet;
knight._pet = nullptr;
}
public:
int _hp = 100;
Pet* _pet;
};
int main()
{
Knight k1;
k1._pet = new Pet();
k1._hp = 1000;
Knight k2;
// k2 = static_cast<Knight&&>(k1);
k2 = std::move(k1);
// move를 한다는 말이 더 이상 k1을 쓰지않겠다는 말과 동일함.
}
Example2
std::unique_ptr<Knight> uptr = std::make_unique<Knight>();
std::unique_ptr<Knight> uptr2 = uptr; // Error : unique_ptr은 복사가 안됨.
std::unique_ptr<Knight> uptr2 = std::move(uptr); // Okay : 권한을 넘긴다.