L-value vs. R-value

 

인프런 Rookiss님의 'Part1: C++ 프로그래밍 입문' 강의를 기반으로 정리한 필기입니다. 
😎[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 강의 들으러 가기!

 

 


 

L value

 

L value : 단일식을 넘어서 계속 지속되는 개체

 

  • 메모리 위치를 참조.
  • 주소가 있는 애들. 대개 식별자.
  • const가 붙으면 수정할 수 없는 l-value가 된다.

 

R value

 

R value : L value가 아닌 나머지 (임시 값, 열거형, 람다, i++ 등)

 

  • 표현식 종료 후 없어지는임시적인 값 리터럴 임시변수 임시객체. 
  • const 로 L value를 R value로 바꿀 수 있다.

 


 

 

 

L value Reference  vs.  R value Reference

 

L value Reference

  • 원본을 넘겨준다.
  • 원본 수정이 가능하다.

 

const L value Reference

  • 원본을 넘겨준다.
  • 원본 수정이 불가능하다. const로 원본 수정을 못하게 막아서 읽기만 하게 한다.

 

 

R value Reference

  • 원본을 넘겨준다.
  • 원본 수정이 가능하다.
  • 이동! 함수가 이동되었다. 함수가 대체되어 원본은 더 이상 사용하지 않는다.
  • R value Reference(오른값 참조)를 받는 '이동 대입 연산자 '와 함께 활용이 가능하다.

 

 

 

 

코드

 

더보기
#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <map>
#include <set>
#include <algorithm>
using namespace std;

// rvalue reference와 std::move

class Pet { };

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

    // 복사 생성자
    Knight(const Knight& knight) { cout << "const Knight&" << endl; }

    // 이동 생성자
    Knight(Knight&& knight) {  }

    ~Knight()
    {
        if (_pet)
            delete _pet;
    }

    // 복사 대입 연산자
    void operator=(const Knight& knight)
    {
        cout << "operator=(const 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 = nullptr;
};

void TestKnight_Copy(Knight knight) { }
void TestKnight_LValueRef(Knight& knight) { } //왼값 참조
void TestKnight_ConstLValueRef(const Knight& knight) { }
void TestKnight_RValueRef(Knight&& knight) { } //오른값 참조, 이동 대상!

int main()
{
    // 왼값(lvalue) vs 오른값(rvalue)
    // - lvalue : 단일식을 넘어서 계속 지속되는 개체
    // - rvalue : lvalue가 아닌 나머지 (임시 값, 열거형, 람다, i++ 등)

    //int a = 3;

    Knight k1;

    TestKnight_Copy(k1);

    TestKnight_LValueRef(k1);
    //TestKnight_LValueRef(knight());

    TestKnight_ConstLValueRef(Knight());

    TestKnight_RValueRef(Knight());

    TestKnight_RValueRef(static_cast<Knight&&>(k1));

    Knight k2;
    k2._pet = new Pet();
    k2._hp = 1000;

    // 원본은 날려도 된다 << 는 Hint를 주는 쪽에 가깝다!
    Knight k3;
    //k3 = static_cast<Knight&&>(k2);
    
    k3 = std::move(k2); // 오른값 참조로 캐스팅
    // std::move의 본래 이름 후보 중 하나가 rvalue_cast

    std::unique_ptr<Knight> uptr = std::make_unique<Knight>();
    std::unique_ptr<Knight> uptr2 = std::move(uptr);

    return 0;
}

 

 

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <iostream>
using namespace std;
#include <vector>
#include <list>
#include <deque>
#include <map>
#include <set>
#include <algorithm>
 
// rvalue reference와 std::move
 
class Pet
{
 
};
 
class Knight
{
public:
    Knight()
    {
        cout << "Knight()" << endl;
    }
 
    // 복사 생성자
    Knight(const Knight& knight)
    {
        cout << "const Knight&" << endl;
    }
 
    // 이동 생성자
    Knight(Knight&& knight)
    {
 
    }
 
    ~Knight()
    {
        if (_pet)
            delete _pet;
    }
 
    // 복사 대입 연산자
    void operator=(const Knight& knight)
    {
        cout << "operator=(const 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 = nullptr;
};
 
void TestKnight_Copy(Knight knight) { }
void TestKnight_LValueRef(Knight& knight) { } //왼값 참조
void TestKnight_ConstLValueRef(const Knight& knight) { }
void TestKnight_RValueRef(Knight&& knight) { } //오른값 참조, 이동 대상!
 
int main()
{
    // 왼값(lvalue) vs 오른값(rvalue)
    // - lvalue : 단일식을 넘어서 계속 지속되는 개체
    // - rvalue : lvalue가 아닌 나머지 (임시 값, 열거형, 람다, i++ 등)
 
    //int a = 3;
 
    Knight k1;
 
    TestKnight_Copy(k1);
 
    TestKnight_LValueRef(k1);
    //TestKnight_LValueRef(knight());
 
    TestKnight_ConstLValueRef(Knight());
 
    TestKnight_RValueRef(Knight());
 
    TestKnight_RValueRef(static_cast<Knight&&>(k1));
 
    Knight k2;
    k2._pet = new Pet();
    k2._hp = 1000;
 
    // 원본은 날려도 된다 << 는 Hint를 주는 쪽에 가깝다!
    Knight k3;
    //k3 = static_cast<Knight&&>(k2);
    
    k3 = std::move(k2); // 오른값 참조로 캐스팅
    // std::move의 본래 이름 후보 중 하나가 rvalue_cast
 
    std::unique_ptr<Knight> uptr = std::make_unique<Knight>();
    std::unique_ptr<Knight> uptr2 = std::move(uptr);
 
 
    return 0;
}
 
cs

'⭐ Programming > C++' 카테고리의 다른 글

callback 함수  (0) 2023.09.18
[C++] smart pointer  (0) 2022.04.26
[C++] 콜백 함수 (Callback function)  (0) 2022.04.17
[C++] 템플릿(Template) 2: 클래스 템플릿  (0) 2022.04.17
[C++] 템플릿(Template) 1: 함수 템플릿  (0) 2022.04.16