관리 메뉴

기억을 위한 기록들

[CPP-effective] 3-1 자원 관리에는 객체가 그만! 본문

C & CPP/Effective C++

[CPP-effective] 3-1 자원 관리에는 객체가 그만!

에드윈H 2021. 4. 1. 14:35

캐릭터의 정보가 있는 캐릭터 클래스가 있고 객체를 사용자가 얻어내는 용도로 팩토리 함수만을 쓰도록 만들어져 있다고 가정해봅시다.

 

 

class Character{
   //...
   Character* CreateCharacter();
   //...
};

 

함수를 통해 얻어낸 객체를 사용할 일이 없어질때, 해당 객체를 삭제해야 할 쪽은 이 함수의 호출장비니다.

 

아래 임시 함수에서 그렇게 만들었다고 합시다.

 

void DoSomething()
{
   //...
   Character* newCharacter= Character::CreateCharacter();
   
   //..
   
   delete newCharacter;
}

 

문제가 없어보이지만, 중간의 주석 부분에서 중간 return이나 예외처리 등 delete까지 닿지 않게되면 메모리누수(memory leak)이 발생하는등 문제가 생깁니다.

 

물론, 혼자서 하나하나 따져가면서 꼼꼼하게 하면 이런 문제는 생기지 않을수가 있습니다. 그런데 오랜 시간동안 혼자가 아닌 여러명의 프로그래머가 유지보수를 하며, 해당 코드가 길어지게 되면 파악하지 못하게 되고 문제가 생길 수도 있다는 점입니다. 항상 delete로 가줄거라고 믿지마시길 바랍니다. 오래가지 못할겁니다.

 

(책에서는 auto_ptr과 tr1의 shared_ptr으로 나와 있으나, C++11에서 auto_ptr의 단점이 있어, 사라지고 unique_ptr이 생겼다.)

 

결국에는 항상 해제 되도록 해주어야 하는데 이것이 바로 스마트포인터입니다. 이전에 작성한글이 있다.

hyo-ue4study.tistory.com/247

 

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

스마트 포인터는 3가지가 있다. - unique_ptr (유니크) - shared_ptr (쉐어드) - weak_ptr (위크) 우선 일반 포인터를 보면 //... int main() { Vector* myVector = new Vector(10.f, 30.f); //... delete myVecto..

hyo-ue4study.tistory.com

스마트포인터는 두가지 특징이 있습니다.

 

1. 자원을 획득한 후에 자원 관리 객체에게 넘깁니다.

자원관리에 객체를 사용하는 아이디어에 대한 업계 용어도 자주 통용 되고 있는데 자원 획득 즉 초기화(Resource Acquition is Initialization : RAII) 라는 이름입니다. 요약하면 "자원을 획득하고 나서 바로 자원관리 객체에 넘겨준다"는 점은 같습니다.

 

2. 자원 관리 객체는 자신의 소멸자를 사용해서 자원이 확실히 해제되도록 합니다.

소멸자는 어떤 객체가 소멸될 때 자동적으로 호출되기 때문에, 실행 제어가 어떤 경위로 블록을 떠나는가에 상관없이 자원해제가 제대로 이루어지게 되는 것입니다.

 

 

void DoSomething()
{
	//...
	Character* newCharacter = Character::CreateCharacter();
	std::shared_ptr<Character> newCharacter2(Character::CreateCharacter()); //추가
	//..

	delete newCharacter;
      //newCharacter2는 해제 필요 x
}

정리

* 자원 누출을 막기 위해, 생성자 안에서 자원을 획득하고 소멸자에서 그것을 해제하는 RAII객체를 사용합시다.

* 일반적으로 널리쓰이는 RAII클래스는 unique 포인터, shared 포인터, weak 포인터가 있습니다.