전체 코드

🚀 1. 개요

C++11에서 도입된 오른값 참조(rvalue reference)std::move자원의 이동(Move) 및 성능 최적화를 위해 등장한 개념입니다.
오른값 참조(&&) → 임시 객체(오른값)의 자원을 효율적으로 이동하는 메커니즘.
std::move → 객체를 오른값(rvalue) 참조로 변환하여 이동 연산을 수행할 수 있도록 함.

이 문서에서는 rvalue referencestd::move의 필요성과 동작 원리를 예제 코드와 함께 상세히 분석하겠습니다.


📂 2. 코드 분석

🎯 클래스 Pet 정의

class Pet { };

Pet 클래스

  • 단순한 클래스이며, Knight 클래스의 멤버로 사용됩니다.
  • 별다른 동작 없이 객체 생성 및 할당을 위한 보조 클래스입니다.

🎯 기본 클래스 Knight

class Knight
{
public:
    Knight()
    {
        cout << "Knight()" << endl;
    }

기본 생성자

  • Knight 객체가 생성될 때 "Knight()"을 출력합니다.
  • 기본적으로 _hp = 100, _pet = nullptr로 초기화됩니다.

🎯 복사 생성자

    Knight(const Knight& knight)
    {
        cout << "const Knight&" << endl;
    }

복사 생성자

  • 기존 Knight 객체를 복사하여 새 객체를 생성합니다.
  • "const Knight&" 출력 → 복사 생성자가 호출됨을 확인.
  • 깊은 복사(Deep Copy) 시 별도 메모리 할당이 필요합니다.

🎯 소멸자

    ~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&&)" 출력 → 이동 대입 연산자가 호출됨을 확인.
  • 이동(Move) 방식 적용
    • _pet 포인터를 이전 객체에서 현재 객체로 이동.
    • 기존 객체의 _petnullptr로 설정하여 더 이상 메모리를 해제하지 않도록 함.
  • 장점: 기존의 복사 방식보다 훨씬 효율적(메모리 복사 없이 주소값만 변경).

🎯 멤버 변수 정의

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) vs 오른값(rvalue)

    // - lvalue : 단일식을 넘어서 지속되는 개체 (변수)
    // - rvalue : lvalue가 아닌 나머지 (임시 값, 표현식, 람다, i++ 등)

왼값 vs 오른값

  • 왼값(lvalue): 변수를 포함해 지속적으로 존재하는 개체 (int a = 3;).
  • 오른값(rvalue): 임시 값(한번 사용된 후 사라지는 값, 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)으로 변환하여 이동 대입 연산자를 호출.
  • k3k2의 자원을 가져오고, 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로 이동.
  • 이동 후 uptrnullptr이 되어 더 이상 객체를 소유하지 않음.

profile
李家네_공부방

0개의 댓글