2 분 소요

개요

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