관리 메뉴

기억을 위한 기록들

[CPP]스마트(Smart) 포인터에 관하여(2) - shared_ptr 본문

C & CPP/Smart Pointer

[CPP]스마트(Smart) 포인터에 관하여(2) - shared_ptr

에드윈H 2021. 2. 18. 22:27

 

shared_ptr

공유포인터로 이전에 유니크 포인터와 달리 원시포인터를 독차지 하지 않고 여럿이서 공유 할 수있다.

몇명(?)이서 공유하는지 확인하기 위해 참조카운팅 기반으로 작동이 된다. 참조 카운팅이란 이전에 작성한 글이 있다.

 

사용예를 보면,

#include <memory>
#include "myVector.h"

int main()
{
    std::shared_ptr<myVector> vector01 = std::make_shared<myVector>(10.f, 30.f);
    // ...
}

위와같이 생성하면 

1 강한 참조 (1 strong ref)가 표시되는걸 확인할 수 있다.

 

shared_ptr 내부

- 두개의 포인터를 소유
 1. 데이터(원시 포인터)를 가리키는 포인터
 2. 제어 블록을 가리키는 포인터(참조카운팅용)
- 유니크 포인터와 달리 shared_ptr 포인터를 다른 shared_ptr 포인터와 공유 가능
- 참조 카운팅 기반
- 원시포인터는 어떠한 쉐어포인트에게도 참조되지 않을 때 소멸된다.

 

공유가능 예

#include <memory>
#include "Vector.h"

int main()
{
    std::shared_ptr<Vector> vector = std::make_shared<Vector>(10.f, 30.f);
    std::shared_ptr<Vector> anotherVector(vector); //공유 가능
    // ...
}

위 처럼 한 공유포인터를 다른 공유 포인터(anotherVector)에게도 공유 하게 된다면 강한 참조는

2가 된다. 그리고 영역(scope)를 벗어나게 되면, 다시 1로 줄어든다.

그리고 강한참조가 0이 되면 해당 메모리는 해제(delete)하게 된다.

 

 

공유 한뒤, 포인터 재설정하기

#include <memory>
#include "Vector.h"

int main()
{
    std::shared_ptr<Vector> vector = std::make_shared<Vector>(10.f, 30.f);
    std::shared_ptr<Vector> anotherVector(vector);
    vector.reset(); //vector=nullptr;과 동일하다.
    //실행기 vector는 nullptr 되고, anotherVector가  <Vector>(10.f, 30.f) 소유한다.
    //reset() 실행시 참조 카운트 1줄어듦.
    // ...
}

 

참조 횟수 구하기

#include <memory>
#include "Vector.h"

int main()
{
    std::shared_ptr<Vector> vector = std::make_shared<Vector>(10.f, 30.f);
    vector.use_count(); //참조 횟수 구하기 출력 1
    
    std::shared_ptr<Vector> anotherVector(vector);
    vector.use_count(); //참조 횟수 구하기 출력 2
    anotherVector.use_count(); //참조 횟수 구하기 출력 2
    // ...
}

 

 

공유 포인터의 문제점

공유가 가능하다보니 생기는 문제는 바로 "서로 공유"하게 되는 것이다.

예)

#include <memory>
using namespace std;
class YourVector;

class MyVector
{
public:
	MyVector(float a, float b)
	{};

	std::shared_ptr<YourVector> yourVectorptr;
};
class YourVector
{
public:
	YourVector(float a, float b)
	{};

	std::shared_ptr<MyVector> myVectorptr;
};

int main()
{
	MyVector* Origin = new MyVector(2.0f, 1.0f);	
	{
		std::shared_ptr<MyVector> myVec(Origin);
		std::shared_ptr<YourVector> yourVec = std::make_shared<YourVector>(10.f, 30.f);

		myVec->yourVectorptr = yourVec;
		yourVec->myVectorptr = myVec;		
	}
	return 0;
}

위와 같은 작동을 하면서 서로를 공유하게 되면 영역(scope)를 벗어나더라도,

서로 참조하게 되면서 참조 카운팅이 없어지지 않기 때문에 자동 해제(delete)가 되지 않는다.....

 

이런 문제를 해결해주는 것이 다음에 나오는 weakptr(약한 포인터) 이다.