책 정리/Effective C++ 3rd

항목 13. 자원 관리에는 객체가 그만!

ocean20 2019. 12. 19. 12:17

팩토리 메서드를 미리 숙지하고 13장을 살펴보자.

 

1. 팩토리 패턴

class Investment() { // 투자 관련 최상위 클래스
… };

class InvestmentA : Investment() {  //파생클래스
… };

class Creator {
public :
Investment* Operation() { return factoryMethod(); }
protected :
virtual Investment* factoryMethod() = 0 ;
};

class CreatorA : Creator{
private:
Investment* factoryMethod() { return new InvestmentA }; // 투자 파생클래스 객체를 동적할당하고 그 포인터를 반환한다. 따라서 객체의 해제는 호출자 쪽에서 직접 해야합니다.
};

위 코드는 일반적인 팩토리 패턴의 예이다.

void f()
{
 InvestmentA *pInv = CreatorA.fatoryMethod(); // 팩토리 함수 호출
  …  //??!
  delete pInv;  // 객체 해제
}

void f()함수는 제대로 코드로 보이지만, 객체 삭제의 실패할 있는 가능성이 높다.

  (1) "…" 구간에서 return

  (2) 생성과 해제가 같은 루프일때, continue goto 섞여있을경우

  (3) "…"에서 예외발생

 

f() 객체를 제대로 해제 해줄거라고 믿으면 안된다.

 

2. 해결방법

  - 자원을 객체에 넣고 자원해제를 소멸자가 맡게한다. 소멸자는 실행제어가 f() 떠날때 호출되도록 만들어야 한다.

  이 아이디어는 이미 표준라이브러리에 만들어져 있다.

  (1) auto_ptr (스마트 포인터)

  (2) tr1::shared_ptr

 

(1) 스마트포인터를 활용하여 f() 다시 작성해보자.

void f()
{
 std::auto_ptr<InvestmentA> pInv(CreatorA.fatoryMethod()); //동일
  …  //pInv 사용
} //auto_ptr의 소멸자를 통해 pInv를 삭제한다.

3. 자원관리 두가지 특징

  (1) 자원 획득후 자원 관리 객체에게 넘긴다.

    - Resource Acquisition Is Initialization (RAII : 자원 획득 초기화)

  (2) 자원 관리 객체는 소멸자를 사용해서 자원이 확실히 해제하도록 한다.

 

auto_ptr 자신이 소멸될때 자신이 가리키는 객체를 삭제하기 때문에, 객체를 가리키는 auto_ptr 2개이상이면 절대로 안되겠다. 그리고 auto_ptr auto_ptr객체를 복사대입하면 기존 auto_ptr 데이터를 NULL 만든다.

 

STL 컨테이너 같은경우는 auto_ptr 성질이 상반되기 때문에 위에 기재한 tr1:;shared_ptr 사용한다.

이유는 여기를 참고해보자.

 

이것만은 잊지말자!

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

  (2) 자주 쓰이는 RAII 클래스는 auto_ptr tr1::shared_ptr이다. 가운데 tr1::shared_ptr 복사 동작이 직관적이기 때문에 놈이 대개 좋습니다.