본문 바로가기
개발/C, C++

C++ 스마트 포인터 : shared_ptr

by 피로물든딸기 2021. 10. 12.
반응형

C, C++ 전체 링크

 

shared_ptr은 포인팅 횟수를 계산해서 0이 되면 객체를 소멸하는 스마트 포인터이다.

 

아래 코드의 결과를 확인해보자.

#include <stdio.h>
#include <memory> // shared_ptr header
#include <iostream>

using namespace std;

class FOOD
{
private:
	int price = 0;
public:
	FOOD() { printf("FOOD created\n"); }
	~FOOD() { printf("FOOD deleted\n"); }

	virtual void printName() { cout << "FOOD Class" << endl; }
	virtual void printPrice() { cout << this->price << endl; }
	void printLine() { cout << "=================" << endl; }
};

int main(void)
{
	cout << "start main\n" << endl;

	shared_ptr<FOOD> myFood(new FOOD);
	cout << "my count : " << myFood.use_count() << endl;
	cout << "\nmy address : 0x" << myFood.get() << endl;

	{
		shared_ptr<FOOD> sharedFood(myFood);
		//shared_ptr<FOOD> sharedFood;
		//sharedFood = myFood;

		cout << "\nmy count : " << myFood.use_count() << endl;
		cout << "sh count : " << sharedFood.use_count() << endl;
		cout << "\nmy address : 0x" << myFood.get() << endl;
		cout << "sh address : 0x" << sharedFood.get() << endl;
	}

	cout << "\nmy count : " << myFood.use_count() << endl;
	cout << "my address : 0x" << myFood.get() << endl;

	cout << "\nend main\n" << endl;

	return 0;
}

 

처음에 new FOOD로 myFood를 생성하였고,

share_ptr의 use_count 메서드로 현재 포인팅하는 포인터 개수가 1임을 알 수 있다.

 

다음 스코프에서 shareFood는 myFood로 생성하였고, 두 객체의 use_count가 모두 2임을 알 수 있다.

그리고 get 메서드를 통해 주소를 확인해보면 같은 포인터임을 알 수 있다.

 

스코프가 끝나서 shareFood에 참조할 수 없더라도, use_count가 1이기 때문에 객체는 소멸되지 않았다.

그리고 main문이 종료되면 FOOD 객체가 소멸되는 것을 알 수 있다.

 

그리고 shared_ptr의 아래의 코드는 아래와 같이 변경하여도 같은 동작을 한다.

//shared_ptr<FOOD> shareFood(myFood);
shared_ptr<FOOD> sharedFood;
sharedFood = myFood;

 

 

auto_ptr과 달리 myFood가 NULL이 되지 않는다.

 

reset 메서드를 이용하면 현재 참조하는 포인터를 즉시 삭제할 수 있다.

shared_ptr<FOOD> shareFood(myFood); 아래에 reset을 추가하고 end main 전에 myFood에 reset을 해보자.

{
	shared_ptr<FOOD> sharedFood(myFood);
	//shared_ptr<FOOD> sharedFood;
	//sharedFood = myFood;
		
	sharedFood.reset();

	cout << "\nmy count : " << myFood.use_count() << endl;
	cout << "sh count : " << sharedFood.use_count() << endl;
	cout << "\nmy address : 0x" << myFood.get() << endl;
	cout << "sh address : 0x" << sharedFood.get() << endl;	
}

myFood.reset();

cout << "\nmy count : " << myFood.use_count() << endl;
cout << "my address : 0x" << myFood.get() << endl;

cout << "\nend main\n" << endl;

sharedFood의 use_count는 0이 되고, address는 NULL이 되었다.

myFood의 포인팅 횟수가 감소하였으므로 1이 된 것을 알 수 있다.

 

그리고 스코프 종료 후 myFood의 reset으로 main 종료 전에 FOOD deleted가 실행되었다.

count가 0이 되자마자 객체가 소멸된 것을 알 수 있다.

 

shared_ptr은 배열로 된 객체도 삭제할 수 있다.

단, 개발자가 삭제하는 함수를 직접 만들어서 등록해야 한다.

객체를 삭제하는 함수 deleteObjects를 만들어서 myFood를 생성할 때 넘겨주면 된다.

void deleteObjects(FOOD* foods)
{
	cout << "delete array" << endl;
	delete[] foods;
}

int main(void)
{
	cout << "start main\n" << endl;

	shared_ptr<FOOD> myFood(new FOOD[5], deleteObjects);
	cout << "my count : " << myFood.use_count() << endl;
	cout << "\nmy address : 0x" << myFood.get() << endl;

	{
		shared_ptr<FOOD> sharedFood(myFood);
		//shared_ptr<FOOD> sharedFood;
		//sharedFood = myFood;

		cout << "\nmy count : " << myFood.use_count() << endl;
		cout << "sh count : " << sharedFood.use_count() << endl;
		cout << "\nmy address : 0x" << myFood.get() << endl;
		cout << "sh address : 0x" << sharedFood.get() << endl;
	}

	cout << "\nmy count : " << myFood.use_count() << endl;
	cout << "my address : 0x" << myFood.get() << endl;

	cout << "\nend main\n" << endl;

	return 0;
}

 

만들어진 5개의 객체가 모두 소멸되는 것을 알 수 있다.

 

shared_ptrauto_ptr을 완전 대체할 수 있으므로 shared_ptr을 사용하면 된다.

 

최종 코드는 아래를 참고하자.

#include <stdio.h>
#include <memory> // shared_ptr header
#include <iostream>

using namespace std;

class FOOD
{
private:
	int price = 0;
public:
	FOOD() { printf("FOOD created\n"); }
	~FOOD() { printf("FOOD deleted\n"); }

	virtual void printName() { cout << "FOOD Class" << endl; }
	virtual void printPrice() { cout << this->price << endl; }
	void printLine() { cout << "=================" << endl; }
};

void deleteObjects(FOOD* foods)
{
	cout << "delete array" << endl;
	delete[] foods;
}

int main(void)
{
	cout << "start main\n" << endl;

	shared_ptr<FOOD> myFood(new FOOD[5], deleteObjects);
	cout << "my count : " << myFood.use_count() << endl;
	cout << "\nmy address : 0x" << myFood.get() << endl;

	{
		shared_ptr<FOOD> sharedFood(myFood);
		//shared_ptr<FOOD> sharedFood;
		//sharedFood = myFood;

		cout << "\nmy count : " << myFood.use_count() << endl;
		cout << "sh count : " << sharedFood.use_count() << endl;
		cout << "\nmy address : 0x" << myFood.get() << endl;
		cout << "sh address : 0x" << sharedFood.get() << endl;
	}

	cout << "\nmy count : " << myFood.use_count() << endl;
	cout << "my address : 0x" << myFood.get() << endl;

	cout << "\nend main\n" << endl;

	return 0;
}
반응형

댓글