Updated:

2 minute read

개요

  • 자동으로 객체를 소멸해주는 포인터
  • 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