Modern C++ - 스마트 포인터

진경천·2024년 3월 20일
0

C++

목록 보기
87/90

스마트 포인터

포인터처럼 동작하는 클래스 탬플릿으로, 사용이 끝난 메모리를 자동으로 해제해준다.

  • unique_ptr
  • shared_ptr
  • weak_ptr

위 3가지 종류가 있다.

unique_ptr

하나의 스마트 포인터만이 특정 객체를 소유할 수 있도록 독점 소유권을 가진다.
해당 객체의 소유권을 가지고 있을 때만 소멸자가 해당 객체를 삭제할 수 있다.

#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 처럼 복사를 하려하면 에러가 발생한다.

p1p0의 소유권을 이전 받았으며 생성된 객체는 1개 뿐이것을 알 수 있다.

shared_ptr

하나의 특정 객체를 참조하는 스마트 포인터가 총 몇개인지를 참조하는 스마트 포인터이다.
참조하고 있는 스마트 포인터의 개수를 참조 횟수(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

weak_ptr

하나 이상의 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에 포함되지 않으며 해제가 된다.

profile
어중이떠중이

0개의 댓글