스마트 포인터(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 |