[C++] 스마트 포인터
Updated:
개요
- 자동으로 객체를 소멸해주는 포인터
- 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