반응형
value는 두개로 나뉠 수 있는데
하나는 왼값( lvalue ) 또 하나는 오른값( rvalue )
int a = 5;
위 코드에서 a가 왼값이고 5가 오른값이라고 할 수 있음
즉 왼값은
- 단일식을 넘어서 계속 지속되는 개체를 뜻함
오른값
- 왼값이 아닌 나머지로 임시 값, 열거형, 람다, i++ 등이 오른 값에 해당함
void TestKnight_Copy(Knight knight) { }
void TestKnight_LValueRef(Knight& knight) { }
void TestKnight_ConstLValueRef(const Knight& knight) { }
// &&를 넣으면 오른값을 넣을 수 있음 대신 왼값은 못넣음
void TestKnight_RValueRef(Knight&& knight) { }
TestKnight_Copy(k1);
TestKnight_LValueRef(*k1);
// Knight()는 함수가 끝나면 없어지는데 멤버변수의 값을 바꾸는 불필요한 행동을 방지하기 위해 막혀있음
TestKnight_LValueRef(Knight()); // 오류
// const를 붙여주면 맴버변수를 건드리지 못하니까 허용은 됨
TestKnight_ConstLValueRef(Knight());
TestKnight_RValueRef(Knight());
보통 객체를 오른값으로 생성해서 인자로 보내는건 불가능하지만
&&를 붙여주면 오른값을 정상적으로 보내는게 가능함
그렇다면 이걸 어디다 쓸까!?
// 이동 대입 연산자
void operator=(Knight&& knight) noexcept
{
cout << "operator=(Knight&& knight)" << endl;
_hp = knight._hp;
_pet = knight._pet;
knight._pet = nullptr;
}
Knight k2;
k2._pet = new Pet();
k2._hp = 1000;
// 원본은 날려도 된다는 Hint로 생각하면 됨
Knight k3;
k3 = static_cast<Knight&&>(k2);
기본적으로 이동 대입 연산자에서 많이 사용되는데
lvalue인 k2를 ravlue로 캐스팅하고 k3에 대입 연산을 하면
Knight&& knight를 인자로 받는 이동 대입 연산자에 들어감
즉 원본은 날려도 된다고 암시하는게 됨 ( 그 이상의 의미는 크게 없다고 봐도 무방 )
이러한 이동 대입 연산자를 사용하는게 바로
std::move임
k3 = std::move(k2); // 오른값 참조로 캐스팅
사실 이러한 오른값 캐스팅 방법을 이용한 이동 대입 연산은
실제로 데이터가 이동되어서 원래 있던 자리에 데이터가 삭제되는건 아니기 때문에
특수한 상황이 아니면 사용하면 안됨
특수한 상황의 예
std::unique_ptr<Knight> uptr = std::make_unique<Knight>();
std::unique_ptr<Knight> upp = uptr; // 오류
std::unique_ptr<Knight> upp = std::move(uptr);
unique_ptr 단 하나만 존재할 수 있는 포인터라고 할 수 있음 때문에
같은 주소값을 들고 있는 객체가 있으면 안되기에 대입 연산이 막혀있음
이럴때 이동 대입 연산을 이용하면 깔끔하게 ptr의 이동이 가능함
반응형
LIST
'프로그래밍 > C++' 카테고리의 다른 글
C++ Lambda (0) | 2022.11.10 |
---|---|
전달 참조(보편 참조)와 forward (0) | 2022.11.09 |
using, typedef (0) | 2022.11.09 |
중괄호 초기화와 initializer_list (0) | 2022.11.08 |
STL algorithm (0) | 2022.11.08 |