C++

순환문제

춤추는수달 2022. 3. 28. 04:01

순환문제란 shared_ptr을 서로 교차해서 참조하는 경우에 그 포인터를 해제시켜도 해제되지 않고 메모리에 계속 남아있는 현상을 말한다. 아래 상황을 보자. (참고로 코드를 직접 실행해 보지는 않았음 그냥 상황만 보셈)

class Knight
{
	sharerd_ptr<Knight> _target;
}

void main()
{
	sharerd_ptr<Knight> k1 = make_shared<Knight>();
    sharerd_ptr<Knight> k2 = make_shared<Knight>();
    
    k1._target = k2;
    k2._target = k1;
    
    k1 = nullptr;
    k2 = nullptr;
}

위처럼 두 Knight 객체의 스마트 포인터가 서로를 참조하고 있을 때, k1과 k2가 서로의 Reference Count를 증가시키고 있다.

이 때 우리 생각대로라면 k1 = nullptr이 되었을 때 k1 자체의 Reference Count도 감소하고, k2의 Reference Count도 k1의 소멸자가 호출되었을 때 멤버 변수인 _target의 소멸자도 같이 호출되면서 감소하게 되어야 한다. 그러나 k2가 k1을 참조하고 있어 Reference Count가 0이 되지 않아 소멸자가 호출되지 못하면서 k2의 Reference Count가 1 남게된다. 마찬가지로 k1도 1 남아서 결국 둘 다 소멸하지 못하게 된다.

 

이렇게 서로 참조하는 상황 뿐만 아니라 한 클래스가 다른 클래스를 소유하는 상황에서도 많이 발생한다. 예를 들어보자.

class Knight
{
	shared_ptr<Knight> _target;
    shared_ptr<Inventory> _inven;
}

class Inventory
{
	Inventory(Knight){}
	shared_ptr<Knight> _owner;
}

void main()
{
	sharerd_ptr<Knight> k1 = make_shared<Knight>();
    k1->_inven = new Inventory(k1);

}

위처럼 소유되는 상황에서도 상호참조가 발생한다.

 

해결 방법

1. 일단 사용자가 상호 참조를 조심하면서 사용하는 방법이 있다. 위 같은 상황이 발생하지 않도록 조심하자.

예를 들어 두 번째 상황에서 shared_ptr<Knight> _owner; 문장을 Knight& _owner; 로 변경하면 해결된다. Inventory 클래스는 Knight 클래스 객체의 Reference Count를 증가시키지 않게 되므로.

 

2. weak_ptr로 해결 가능하다. weak_ptr 사용에 대해서는 다음 글에서 스마트 포인터들을 공부하며 같이 알아보자.

'C++' 카테고리의 다른 글

Casting (Static, Dynamic, Reinterpret )  (0) 2023.03.28
스마트 포인터  (0) 2022.03.29
STL 컨테이너별 간략 특징 정리  (0) 2022.02.21
TLS(Thread Local Storage)  (0) 2022.02.01
메모리 모델  (0) 2022.02.01