(Modern C++) r-value reference

Posted by : at

Category : Cpp


  • 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 : 권한을 넘긴다.

About Taehyung Kim

안녕하세요? 8년차 현업 C++ 개발자 김태형이라고 합니다. 😁 C/C++을 사랑하며 다양한 사람과의 협업을 즐깁니다. ☕ 꾸준한 자기개발을 미덕이라 생각하며 노력중이며, 제가 얻은 지식을 홈페이지에 정리 중입니다. 좀 더 상세한 제 이력서 혹은 Private 프로젝트 접근 권한을 원하신다면 메일주세요. 😎

Star
Useful Links