스마트 포인터

원래벌레·2022년 8월 1일
0

🌞 SharedPtr의 문제점

  • 자작스마트포인터의 문제점
    이미 만들어진 클래스 대상으로 사용이 불가능하다.
    ex) 상속이 되지 않으면 작동하지 않는다.
  • 자작, 기본 SharedPtr의 문제점
    순환(Cycle)의 문제 : 두개의 객체가 서로를 참조하고 있다라고 했을 때, 순환이 발생한다.
    이 경우 서로가 서로를 참조하고 있어서, Count의 값이 2가 된다. 그런데, 여기서 문제가 발생하게 된다. 서로가 서로를 참조하고 있기 때문에 Release를 발생시켜 준다 하더라도 Count의 값이 0이 되는 일이 생겨나지 않는다. 그렇게 되면 메모리 Leak이 생겨나고 이는 서버 크래쉬를 일으킨다.
using KnightRef = TSharedPtr<class Knight>;

class Knight : public RefCountable
{
public:
	Knight()
	{
		cout << "Knight()" << endl;
	}
	~Knight()
	{
		cout << "~Knight()" << endl;
	}

	void SetTarget(KnightRef target)
	{
		_target = target;
	}
private:
	KnightRef _target = nullptr;
};


int main()
{
	KnightRef k1(new Knight());
	k1->ReleaseRef();
	KnightRef k2(new Knight());
	k2->ReleaseRef();

	k1->SetTarget(k2);
	k2->SetTarget(k1);

	k1 = nullptr;
	k2 = nullptr;
}

🌞 여러가지 스마트포인터

🌼 UniquePtr

  • 복사를 막고 있는 특징이 있다.(이동은 가능 nullptr로 초기화가 안될듯 하다.)
  • 어려운 작업을 하는건 아니고 간단한 스마트 포인터 작업에 사용된다.
unique_ptr<Knight> k2 = make_unique<Knight>();
unique_ptr<Knight> k3 = k2; // 불가
unique_ptr<Knight> k3 = std::move(k2); // 이동을 해야지 복사가능

🌼 SharedPtr

shared_ptr은 자작으로 만든 상속을 이용한 sharedptr과 다르게, RefCountable을 상속하는 것이 아니라 포인터로써 Count값을 가지고 있다. 그래서 따로 상속이 필요하지 않고, shared_ptr만을 이용하여 사용 할 수 있다. 즉, 클래스와 카운트에 해당하는 메모리 블록 두개를 할당하는 것이다.

shared_ptr<Knight> spr(new Knight());
shared_ptr<Knight> spr = make_shared<Knight>(); // new보다 우아한 방법
shared_ptr<Knight> spr2 = spr; // 복사
  • make_shared vs new
    make_shared를 이용하여 객체를 할당하게 되면, 위에서 말한 두개의 메모리 블록을 각각 할당하는 방식이 아닌, 두개의 메모리 블록을 한꺼번에 저장 할 수 있는 메모리를 할당하여, 두개의 블록을 한 번에 할당하게한다.
  • RefCountingBlock(uses, weaks)
    위에서 말한 카운트블록은 두가지의 카운트를 가지고 있다.
    uses와 weaks다. 자작으로 만든 sharedptr는 한가지의 카운트를 쓴다는 점에서 둘에 차이가 있다.
    1) useCount(sharedCount) : 쉐어드포인터로 참조하고 있는 카운트
    2) weakCount : 위크포인터로 참조하고 있는 카운트

🌼 WeakPtr

위크포인터는 반쪽짜리 스마트 포인터이다. 위에서 말한 RefCountingBlock은 두가지의 카운트 값을 가지고 있다고 했다.
해당 블록의 weakCount가 이 WeaKPtr에 의해서 값이 변동되게 할 수 있다. weakCount는 객체가 null이 될 때 값이 줄어 드는데, 이를 이용하여 Cycle문제를 해결 할 수 있다. 먼저 SharedPtr에 의해서 참조한 값이 0이 되지 않고, 사이클이 발생한다 했을 때 이 경우 RefCountBlock은 delete되지 않았을 것이다. 하지만 weakCount의값은 nullptr을 가리키고 있을 것이다. 이를 이용하여 해당 값이 nullptr인 경우 현재 사이클이 발생 중인 것을 알 수 있다.

  • weakCount값이 nullptr인지 확인하는 두가지 방법
    1) expired 메소드
    2) lock 메소드
shared_ptr<Knight> spr = make_shared<Knight>();
weak_ptr<Knight> wpr = spr;

bool expired = wpr.expired(); 
shared_ptr<Knight> spr2 = wpr.lock(); // 위와 현재 줄 두개는 사이클 해결방법

profile
학습한 내용을 담은 블로그 입니다.

0개의 댓글