본문 바로가기
C++

[C++] 스마트 포인터의 사용법

728x90
반응형

스마트 포인터란?

    - 하나의 객체를 여러곳에서 일반 포인터로 참조하는 경우가 있는데 이때, 아직 객체를 참조하고 있음에도 불구하고 다른곳에서 해당 객체를 할당 해제 시켜버리면 댕글링 포인터(허상 포인터)가 발생합니다. 이러한 현상을 방지 하기 위해 나온것이 바로 스마트 포인터입니다. 스마트 포인터는 객체를 참조하고 있는 포인터를 카운팅하여 참조하는 포인터가 전부 사라지기 전까지는 객체를 할당 해제 하지 않는 기능을 제공합니다.

 

shared_ptr 사용법

#include <iostream>
using namespace std;

class SmartClass
{
public:
	SmartClass() { }
};

int main()
{
	shared_ptr<SmartClass> ptr = nullptr;
	shared_ptr<SmartClass> ptr2 = nullptr;


	cout << "참조 개수 : " << ptr.use_count() << endl;

	ptr = make_shared<SmartClass>();

	cout << "참조 개수 : " << ptr.use_count() << endl;

	ptr2 = ptr;

	cout << "참조 개수 : " << ptr.use_count() << endl;

	ptr2.reset();

	cout << "참조 개수 : " << ptr.use_count() << endl;

	ptr.reset();

	cout << "참조 개수 : " << ptr.use_count() << endl;


	return 0;
}

shared_ptr은 하나의 객체를 가르키는 포인터를 여러개 만들 수 있으며, 객체를 참조하는 포인터가 늘어날 때 마다 count값을 +1해줍니다. 그리고 참조를 끊을 때 마다 -1을 해줌으로써 총 몇개의 포인터가 해당 객체를 참조하고 있는지 확인합니다. 해당 객체를 참조하는 포인터가 더이상 없을시에는 해당 객체를 할당 해제해줍니다.

 

unique_ptr 사용법

#include <iostream>

using namespace std;

class SmartClass
{
public:
	SmartClass() { }
	void Print() { cout << "SmartClass" << endl; }
};

int main()
{
	unique_ptr<SmartClass> ptr(new SmartClass());

	ptr->Print();

	return 0;
}

unique_ptr은 단 한대의 포인터만을 허용하기 때문에 기본적으로 복사나 대입 연산이 불가능합니다. 따라서 최초에 선언을 할 때 에도 생성자를 대입하는 방식이 아니라 매개변수로써 넘겨주는 방식으로 생성합니다.

 

 

weak_ptr 사용법

#include <iostream>
using namespace std;

class SmartClass
{
public:
	SmartClass() { cout << "SmartClass created" << endl; }
	~SmartClass() { cout << "SmartClass destroyed" << endl; }
	shared_ptr<SmartClass> next = nullptr;
};

int main()
{
	shared_ptr<SmartClass> ptrA = nullptr;
	shared_ptr<SmartClass> ptrB = nullptr;

	ptrA = make_shared<SmartClass>();
	ptrB = make_shared<SmartClass>();

	ptrA->next = ptrB;
	ptrB->next = ptrA;

	ptrA.reset();
	ptrB.reset();

	cout << "참조 갯수 : " << ptrA.use_count() << endl;
	cout << "참조 갯수 : " << ptrB.use_count() << endl;

	return 0;
}

위와 같은 상황에서는 분명히 참조갯수가 0개라고 나오지만 실제로는 소멸자가 호출되지 않았다. next변수에 저장된 포인터 때문이다. 이렇게 할당해제가 제대로 이루어지지 않을 때 를 사용되는 것이 바로 weak_ptr이다.

 

#include <iostream>
using namespace std;

class SmartClass
{
public:
	SmartClass() { cout << "SmartClass created" << endl; }
	~SmartClass() { cout << "SmartClass destroyed" << endl; }
	weak_ptr<SmartClass> next;
};

int main()
{
	shared_ptr<SmartClass> ptrA = nullptr;
	shared_ptr<SmartClass> ptrB = nullptr;

	ptrA = make_shared<SmartClass>();
	ptrB = make_shared<SmartClass>();


	ptrA->next = ptrB;
	ptrB->next = ptrA;

	ptrA.reset();
	ptrB.reset();


	cout << "참조 갯수 : " << ptrA.use_count() << endl;
	cout << "참조 갯수 : " << ptrB.use_count() << endl;

	return 0;
}

이렇게 weak_ptr로 바꾸어주면 객체가 정상적으로 할당해제된다.

반응형