포인터처럼 동작하는 클래스 탬플릿으로, 사용이 끝난 메모리를 자동으로 해제해준다.
위 3가지 종류가 있다.
하나의 스마트 포인터만이 특정 객체를 소유할 수 있도록 독점 소유권을 가진다.
해당 객체의 소유권을 가지고 있을 때만 소멸자가 해당 객체를 삭제할 수 있다.
#include <iostream>
#include <memory>
using std::cout;
using std::endl;
struct Test {
int num;
Test(int num) : num(num) {
cout << "Construct : " << num << endl;
}
~Test() {
cout << "Destruct : " << num << endl;
}
};
int main() {
Test* test = new Test(0);
std::unique_ptr<Test> p0(test);
// std::unique_ptr<Test> p1 = p0;
// unique_ptor은 p0와 p1이 scope를 벗어날 때 test를 해제하려 한다.
// unique_ptr은 독점 소유권을 가짐
std::unique_ptr<Test> p1 = std::move(p0);
}
실행 결과
Construct : 0
Destruct : 0
unique_ptr은 소유권을 이전할 수 있지만 복사할 수는 없다.
std::unique_ptr<Test> p1 = p0
처럼 복사를 하려하면 에러가 발생한다.
p1
은 p0
의 소유권을 이전 받았으며 생성된 객체는 1개 뿐이것을 알 수 있다.
하나의 특정 객체를 참조하는 스마트 포인터가 총 몇개인지를 참조하는 스마트 포인터이다.
참조하고 있는 스마트 포인터의 개수를 참조 횟수(reference count)라고 한다.
#include <iostream>
#include <memory>
using std::cout;
using std::endl;
struct Test {
int num;
Test(int num) : num(num) {
cout << "Construct : " << num << endl;
}
~Test() {
cout << "Destruct : " << num << endl;
}
};
int main() {
Test* test = new Test(0);
std::shared_ptr<Test> p0 = std::make_shared<Test>(0);
std::shared_ptr<Test> p1(p0);
cout << p0.use_count() << endl;
cout << p1.use_count() << endl;
}
실행 결과
Construct : 0
Construct : 0
2
2
Destruct : 0
하나 이상의 shared_ptr 인스턴스가 소유하는 객체에 대한 접근을 제공하지만 소유자의 수에는 포함되지 않는 스마트 포인터
shared_ptr은 참조 횟수를 기반으로 동작하기 때문에 서로 상대방을 가리키는 shared_ptr를 가지고 있다면, 참조 횟수는 0이 되지 않아 메모리 해제가 불가하다.
#include <iostream>
#include <memory>
using std::cout;
using std::endl;
struct B;
struct A {
A() { cout << "Construct A" << endl; }
~A() { cout << "Destruct A" << endl; }
std::shared_ptr<B> b;
};
struct B {
B() { cout << "Construct B" << endl; }
~B() { cout << "Destruct B" << endl; }
std::shared_ptr<A> a;
};
int main() {
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->b = b;
b->a = a;
cout << a.use_count() << endl;
cout << b.use_count() << endl;
}
실행 결과
Construct A
Construct B
2
2
a는 b를 가리키고 b는 a를 가리키며 reference count가 2로 유지되어 해제가 되지 않는다.
struct B {
B() { cout << "Construct B" << endl; }
~B() { cout << "Destruct B" << endl; }
std::weak_ptr<A> a;
};
여기서 struct B
의 a를 weak_ptr로 선언해주면
Construct A
Construct B
1
2
Destruct A
Destruct B
위와 같이 a가 reference count에 포함되지 않으며 해제가 된다.