스마트 포인터

C++ 2020. 12. 16. 21:05

스마트 포인터(Smart Pointer)

- 프로그래머의 실수로 메모리 누수를 방지하기 위한 수단으로 포인터처럼 동작하는 클래스 템플릿

- 기본적으로 힙 영역에 동적 할당된 메모리를 해제하기 위해서는 delete 키워드를 쓰면 됨

- 스마트 포인터를 이용하면 메모리 누수를 더 효과적으로 방지할 수 있기 때문에 컴퓨터 시스템의 안정성을 높일 수 있음

- 일반적으로 new 키워드를 이용해서 기본 포인터가 특정한 메모리 주소를 가리키도록 초기화 한 이후에 스마트 포인터에 해당 포인터를 넣어서 사용할 수 있음

- 정의된 스마트 포인터는 수명을 다했을 때 소멸자에서 delete 키워드를 이용해 할당된 메모리들을 자동으로 해제하는 기능을 수행함

- unique_ptr : 하나의 스마트 포인터가 특정한 객체를 처리할 수 있도록 함

- shared_ptr : 특정한 객체를 참조하는 스마트 포인터가 총 몇 개인지를 참조함

- weak_ptr : 하나 이상의 shared_ptr 인스턴스가 소유하는 객체에 대한 접근을 제공

 

unique_ptr

- 하나의 스마트 포인터만이 특정한 객체를 처리하도록 할 때 unique_ptr을 사용할 수 있음

- 스마트 포인터는 특정한 객체의 소유권을 가지고 있을 때만 소멸자가 객체를 삭제할 수 있음

 

* unique_ptr 소유권 이전과 메모리 할당 해제

#include <iostream>
#include <string>
#include <stdio.h>

using namespace std;

int main(void) {
    unique_ptr<int> p1(new int(10));
    unique_ptr<int> p2;
    cout << "스마트 포인터 1: " << p1 << '\n';
    cout << "스마트 포인터 2: " << p2 << '\n';
    cout << "--- 소유권 이전 ---\n";
    p2 = move(p1); // 소유권 이전
    cout << "스마트 포인터 1: " << p1 << '\n';
    cout << "스마트 포인터 2: " << p2 << '\n';
    cout << "--- 메모리 할당 해제 ---\n";
    p2.reset(); // 메모리 할당 해제
    cout << "스마트 포인터 1: " << p1 << '\n';
    cout << "스마트 포인터 2: " << p2 << '\n';
    system("pause");
}

 

* unique_ptr 객체에 접근하기

#include <iostream>
#include <string>
#include <stdio.h>

using namespace std;

int main(void) {
    unique_ptr<int> p1(new int(10));
    cout << *p1 << '\n'; // 관리하고 있는 객체를 반환함
    system("pause");
}

 

* 메모리 해제 이후에 객체에 접근

#include <iostream>
#include <string>
#include <stdio.h>

using namespace std;

int main(void) {
    int* arr = new int[10];
    unique_ptr<int> p1(arr);
    for (int i = 0; i < 10; i++) {
        arr[i] = i;
    }
    for (int i = 0; i < 10; i++) {
        cout << arr[i] << ' ';
    }
    p1.reset();
    cout << '\n';
    for (int i = 0; i < 10; i++) {
        cout << arr[i] << ' ';
    }
    system("pause");
}

 

shared_ptr

- shared_ptrd은 하나의 특정한 객체를 참조하는 스마트 포인터의 개수가 몇 개인지를 참조

- 특정한 객체를 새로운 스마트 포인터가 참조할 때마다 참조 횟수가 1씩 증가하며 각 스마트 포인터의 수명이 다할 때마다 1씩 감소

- 결과적으로 참조 횟수가 0이 되면 delete 키워드를 이용해 메모리에서 데이터를 자동으로 할당 해제

#include <iostream>
#include <string>
#include <stdio.h>

using namespace std;

int main(void) {
    int* arr = new int[10];
    arr[7] = 100;
    shared_ptr<int> p1(arr);
    cout << p1.use_count() << '\n'; // 1
    shared_ptr<int> p2(p1);
    cout << p1.use_count() << '\n'; // 2
    shared_ptr<int> p3 = p2;
    cout << p1.use_count() << '\n'; // 3
    p1.reset();
    p2.reset();
    cout << "arr[7]: " << arr[7] << '\n';
    p3.reset();
    cout << p1.use_count() << '\n';
    cout << "arr[7]: " << arr[7] << '\n';
    system("pause");
}

 

weak_ptr

- weak_ptr은 하나 이상의 shared_ptr 객체가 참조하고 있는 개체에 접근할 수 있음

- 해당 객체의 소유자의 수에는 포함되지 않는 스마트 포인터

- 일반적으로 서로가 상대방을 가리키는 두 개의 shared_ptr이 있다면 참조 횟수는 0이 될 수 없기 때문에 메모리에서 해제될 수 없음

- weak_ptr은 이러한 순환 참조 현상을 제거하기 위한 목적으로 사용할 수 있음

#include <iostream>
#include <string>
#include <stdio.h>

using namespace std;

int main(void) {
    int* arr = new int(1);
    shared_ptr<int> sp1(arr);
    weak_ptr<int> wp = sp1; // wp는 참조 횟수 계산에서 제외
    cout << sp1.use_count() << '\n'; // 1로 통일
    cout << wp.use_count() << '\n';
    if (true) {
        shared_ptr<int> sp2 = wp.lock(); // shared_ptr 포인터 반환
        cout << sp1.use_count() << '\n';
        cout << wp.use_count() << '\n';
    }
    // 스코프를 벗어나므로 sp2가 해제됨
    cout << sp1.use_count() <<'\n';
    cout << wp.use_count() <<'\n';
    system("pause");
}

'C++' 카테고리의 다른 글

STL 시퀀스 컨테이너  (0) 2020.12.16
STL 컨테이너 어댑터  (0) 2020.12.16
템플릿  (0) 2020.12.16
다형성 기법  (0) 2020.12.16
캡슐화 기법  (0) 2020.12.15
Posted by khon98
,