C++11에서 도입된 오른값 참조(rvalue reference)와 std::move는 자원의 이동(Move) 및 성능 최적화를 위해 등장한 개념입니다.
✅ 오른값 참조(&&) → 임시 객체(오른값)의 자원을 효율적으로 이동하는 메커니즘.
✅ std::move → 객체를 오른값(rvalue) 참조로 변환하여 이동 연산을 수행할 수 있도록 함.
이 문서에서는 rvalue reference와 std::move의 필요성과 동작 원리를 예제 코드와 함께 상세히 분석하겠습니다.
Pet 정의class Pet { };
✅ Pet 클래스
Knight 클래스의 멤버로 사용됩니다. Knightclass Knight
{
public:
Knight()
{
cout << "Knight()" << endl;
}
✅ 기본 생성자
Knight 객체가 생성될 때 "Knight()"을 출력합니다. _hp = 100, _pet = nullptr로 초기화됩니다. Knight(const Knight& knight)
{
cout << "const Knight&" << endl;
}
✅ 복사 생성자
Knight 객체를 복사하여 새 객체를 생성합니다. "const Knight&" 출력 → 복사 생성자가 호출됨을 확인. ~Knight()
{
if (_pet)
delete _pet;
}
✅ 소멸자 (~Knight())
_pet이 동적 할당되었을 경우 delete를 수행하여 메모리 누수 방지. void operator=(const Knight& knight)
{
cout << "operator=(const Knight&)" << endl;
// 깊은 복사 수행
_hp = knight._hp;
if (knight._pet)
_pet = new Pet(*knight._pet);
}
✅ 복사 대입 연산자 (=)
"operator=(const Knight&)" 출력 → 복사 대입 연산자가 호출됨을 확인. _pet이 동적 할당된 경우, 새로운 메모리를 할당하여 데이터를 복사. rvalue reference 활용) void operator=(Knight&& knight) noexcept
{
cout << "operator=(Knight&&)" << endl;
// 얕은 복사 (Move)
_hp = knight._hp;
_pet = knight._pet;
// 이동 후 원본 knight의 자원 초기화
knight._pet = nullptr;
}
✅ 이동 대입 연산자 (=)
"operator=(Knight&&)" 출력 → 이동 대입 연산자가 호출됨을 확인. _pet 포인터를 이전 객체에서 현재 객체로 이동. _pet을 nullptr로 설정하여 더 이상 메모리를 해제하지 않도록 함. public:
int _hp = 100;
Pet* _pet = nullptr;
✅ 멤버 변수
_hp: 기본 체력 값(100). _pet: Pet 클래스의 포인터(동적 할당될 수 있음). void TestKnight_Copy(Knight knight) { }
void TestKnight_LValueRef(Knight& knight) { }
void TestKnight_ConstLValueRef(const Knight& knight) { }
void TestKnight_RValueRef(Knight&& knight) { }
✅ 다양한 참조 방식 함수
TestKnight_Copy: 복사 생성자 호출 → Knight knight TestKnight_LValueRef: 왼값 참조(lvalue reference) → Knight& knight TestKnight_ConstLValueRef: 상수 왼값 참조(const lvalue reference) TestKnight_RValueRef: 오른값 참조(rvalue reference) main() 함수 분석int main()
{
✅ 프로그램 실행의 시작점.
// - lvalue : 단일식을 넘어서 지속되는 개체 (변수)
// - rvalue : lvalue가 아닌 나머지 (임시 값, 표현식, 람다, i++ 등)
✅ 왼값 vs 오른값
int a = 3;). 3 + 5, Knight()). Knight k1;
TestKnight_Copy(k1);
TestKnight_LValueRef(k1);
TestKnight_ConstLValueRef(Knight());
TestKnight_RValueRef(Knight());
TestKnight_RValueRef(static_cast<Knight&&>(k1));
✅ 다양한 방식으로 Knight 객체 전달
TestKnight_Copy(k1); TestKnight_LValueRef(k1); TestKnight_RValueRef(Knight()); (임시 객체 전달) std::move 활용) Knight k2;
k2._pet = new Pet();
k2._hp = 1000;
Knight k3;
k3 = std::move(k2);
✅ 이동 대입 연산자 호출 (std::move)
std::move(k2); → k2를 오른값(rvalue)으로 변환하여 이동 대입 연산자를 호출. k3가 k2의 자원을 가져오고, k2._pet = nullptr 설정. std::unique_ptr) 활용 std::unique_ptr<Knight> uptr = std::make_unique<Knight>();
std::unique_ptr<Knight> uptr2 = std::move(uptr);
✅ 소유권 이전
uptr의 소유권을 uptr2로 이동. uptr은 nullptr이 되어 더 이상 객체를 소유하지 않음.