개요
- 자동으로 객체를 소멸해주는 포인터
- unique_ptr
- 소유자가 하나인 포인터
- 더블 프리 방지
- 이동은 가능하지만 복사나 공유는 불가
- 복사 생성자가 명시적으로 삭제되었으므로 복사 불가
- 함수 인자로 전달 시 get 함수를 통해 레퍼런스가 아닌 포인터를 받게 해야 소유자가 하나라는 원칙에 위배되지 않음
- C++14부터 make_unique를 이용하여 간단하게 생성가능
- shared_ptr
- 참조 횟수를 관리하는 포인터
- 참조 횟수가 0이 되면 객체를 소멸
- enable_shared_from_this
- this 이용하여 shared_ptr를 만들고 싶을 경우 사용
- shared_ptr을 사용할 경우 더블 프리 문제 발생
- make_shared를 사용하여 생성
- weak_ptr
- 참조 횟수를 변경하지 않고 shared_ptr의 객체를 참조
- shared_ptr의 순환 참조 문제를 해결하는 포인터
- 직접 접근이 불가하고 shared_ptr로 변환해서 접근 가능
예제
- 코드
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class Test {
public:
int i;
Test(const int &i) : i(i) {}
~Test() { cout << "~Test() : " << this->i << endl; }
void func() { cout << "func() : " << this->i << endl; }
};
class Test2 : public enable_shared_from_this<Test2> {
public:
auto GetSharedPtr() -> decltype(shared_from_this()) {
return shared_from_this();
}
};
void func1() {
Test *pt = new Test(1);
unique_ptr<Test> t1 = make_unique<Test>(2);
t1->func();
auto t2 = move(t1);
auto call = [](Test *t) { t->func(); };
call(t2.get());
cout << "t1.get() : " << t1.get() << endl;
cout << "t2.get() : " << t2.get() << endl;
vector<unique_ptr<Test>> v;
v.emplace_back(new Test(3));
v.back()->func();
throw 1;
delete pt;
}
void func2() {
shared_ptr<Test2> t1 = make_shared<Test2>();
cout << "t1.use_count() : " << t1.use_count() << endl;
{
auto t2(t1);
cout << "t2.use_count() : " << t2.use_count() << endl;
}
auto t3(t1);
cout << "t3.use_count() : " << t3.use_count() << endl;
auto t4(t1->GetSharedPtr());
cout << "t4.use_count() : " << t4.use_count() << endl;
t3.reset();
cout << "t3.get() : " << t3.get() << endl;
cout << "t4.use_count() : " << t4.use_count() << endl;
}
void func3() {
shared_ptr<Test2> s1 = make_shared<Test2>();
cout << "s1.use_count() : " << s1.use_count() << endl;
weak_ptr<Test2> w = s1;
{
auto s2 = w.lock();
cout << "s2.get() : " << s2.get() << endl;
cout << "s1.use_count() : " << s1.use_count() << endl;
}
cout << "s1.use_count() : " << s1.use_count() << endl;
cout << "w.lock() : " << w.lock() << endl;
s1.reset();
cout << "s1.get() : " << s1.get() << endl;
cout << "w.lock() : " << w.lock() << endl;
}
int main() {
try {
func1();
} catch (...) {
}
cout << "------ 1" << endl;
func2();
cout << "------ 2" << endl;
func3();
return 0;
}
- 실행 결과
func() : 2
func() : 2
t1.get() : 0
t2.get() : 0xddaed0
func() : 3
~Test() : 3
~Test() : 2
------ 1
t1.use_count() : 1
t2.use_count() : 2
t3.use_count() : 2
t4.use_count() : 3
t3.get() : 0
t4.use_count() : 2
------ 2
s1.use_count() : 1
s2.get() : 0xddb3e0
s1.use_count() : 2
s1.use_count() : 1
w.lock() : 0xddb3e0
s1.get() : 0
w.lock() : 0