[C++]L-value와 R-value, R-value reference
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 | 
댓글
이 글 공유하기
다른 글
- 
callback 함수
callback 함수
2023.09.18 - 
[C++] smart pointer
[C++] smart pointer
2022.04.26 - 
[C++] 콜백 함수 (Callback function)
[C++] 콜백 함수 (Callback function)
2022.04.17 - 
[C++] 템플릿(Template) 2: 클래스 템플릿
[C++] 템플릿(Template) 2: 클래스 템플릿
2022.04.17