스마트 포인터 공부 1

2023. 7. 27. 18:24개인공부/C++

RAII 

Rsource Acquisition Is Initialize (RAII) 자원 획득을 초기화 한다 ! RAII는 C++ 설계 패턴중인 하나인 키워드로 자원 관리를 스택에 할당한 객체를 통해서 수행하는 것이다. 스택에서 객체를 잡아두고 스택메모리가 해제되면 자동으로 메모리 해제를 하는 방식의 설계인거 같다. 

unique_ptr

C++ 에서 메모리를 잘못된 방식으로 관리하였을때 크게 두 가지 종류의 문제점이 발생하는데 첫번째는 메모리를 사용한 후에 해제하지 않는 경우와 이미 해제된 메모리를 다시 참조하는 문제점이 있다. 이러한 문제가 발생한 이유는 만들어진 객체의 소유권이 명확하지 않아인데 우리가 어떤 포인터에 객체의 유일한 소유권을 부여해서, 이 포인터 말고는 객체를 소멸시킬 수 없다! 라고 한다면 안전

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
#include <iostream>
#include <memory>
 
class A 
{
    int* data;
 
public:
    A(int a) {
        std::cout << "자원을 획득함!" << std::endl;
        data = new int[a];
    }
    A(const A& a) = delete;
 
    void some() { std::cout << "일반 포인터와 동일하게 사용가능!" << std::endl; }
 
    ~A() {
        std::cout << "자원을 해제함!" << std::endl;
        delete[] data;
    }
};
 
void Print2(std::unique_ptr<A> uniqueA)
{
    uniqueA->some();
}
 
void Print(A* a)
{
    a->some();
}
 
void do_something() 
{
    std::unique_ptr<A> pa(new A(6));
    // 일반 포인터로 접근하는 것처럼 unique_ptr로 -> 접근 
    pa->some();
    Print(pa.get());
 
    // unique_ptr은 유일한 객체 소유권을 가지므로 복사생성자가 없다.
    //Print2(pa); (오류)
    
    // get: 스마트포인터가 가리키는 주소를 반환한다.
    A* ptrA = pa.get();
    Print(ptrA);
 
    // release 를 사용해서 메모리 소멸을 명시적으로 호출
    pa.release();
}
 
int main() 
{
    do_something();
    return 0
}
cs

 

unique_ptr 유일한 소유권이다 !

유일한 소유권을 의미하므로 복사생성자를 delete 되는 형식으로 구현되어있다. 그러므로 STL에서 사용하기 위해서는 확실히 std::move 함수를 사용해서 소유권을 이전시켜주고 컨테이너에 추가가 가능하다. emplace_back 의 경우에는 역시 A의 생성자가 아닌 unique_ptr<A>의 생성자를 넣어줘야하므로 아래와같이 사용해야한다!

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
#include <iostream>
#include <vector>
#include <memory>
 
class A 
{
    int* data;
 
public:
    A(int a) {
        std::cout << "자원을 획득함!" << std::endl;
        data = new int[a];
    }
    A(const A& a) = delete;    
 
    void some() { std::cout << "일반 포인터와 동일하게 사용가능!" << std::endl; }
 
    ~A() {
        std::cout << "자원을 해제함!" << std::endl;
        delete[] data;
    }
};
 
 
int main() 
{
    // C++ 14 make_unique 함수 
    auto ptr = std::make_unique<A>(5);
 
    // unique_ptr을 원소로 가지는 컨테이너 
    std::vector<std::unique_ptr<A>> vec; 
    
    std::unique_ptr<A> a(new A(10));
 
    // vec.push_back(a); -> 무시무시한 오류 발생 
    // 결국 unique_ptr은 유일한 소유권(복사생성자 x)을 의미하므로 push_back이 불가능하다 
 
    // std::move 를 사용해서 소유권을 이전한다. 
    vec.push_back(std::move(a));
 
    // emplac_back 의 경우에는 unique_ptr 의 생성자를 넣어줘야하므로 
    //vec.emplace_back(5); <- 이런 경우는 오류가 발생한다. 
    vec.emplace_back(new A(5));
 
    return 0
}
cs

'개인공부 > C++' 카테고리의 다른 글

멀티 쓰레드  (0) 2023.07.24
sizeof  (0) 2023.03.30
const, static 정리  (0) 2023.03.21
복사 생성자, 소멸자 정리  (0) 2023.03.20
함수의 오버로딩, 생성자 정리  (0) 2023.03.19