Item 15: 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있게 하자
1. 자원을 관리해주는 클래스를 만들어서 자원 관리를 효과적으로 적용할 수 있다. 그런데 왜 자원을 직접 접근할 수 있는 방법을 제공해야 하나?
자원을 직접 참조하는 많은 기존 API들이 있다. 이런 이유 때문에 자원 관리 클래스들은 어쩔 수 없이 자신이 관리하는 자원을 사용자가 직접 접근할 수 있는 방법을 제공해야 한다.
std::tr1::shared_ptr<Investment> pInv(createInvetment());
int daysHeld(const Investment *pi);
int days = daysHeld(pInv); // Error !!
위와 같은 에러를 해결하기 위해 아래 같은 코드 필요.
int days = daysHeld(pInv.get()); // 이제 OK.
2. 직접 접근할 수 있는 경로는?
- 해당 자원을 반환하는 함수 작성
shared_ptr 같은 경우 get() 함수가 해당한다.
- 역참조 연산자들 구현(operator-> 및 operator*)
std::tr1::shared_ptr<Investment> pInv(createInvetment());
pInv->isTaxFree();
(*iInv).isTaxFree();
- 암시적 타입 변환 함수
FontHanlde getFont(); // C API, 매개변수 생략
void releaseFont(FontHanlde fh); // C API
class Font { // RAII 클래스
public:
explicit Font(FontHandle fh) // 자원 획득
: f(fh) // 값에 의한 전달!!
{} // 자원 해제를
~Font() { releaseFont(f); } // C API로 하기 때문임.
FontHandle get() { return f; } // 명시적 변환 함수
private:
FontHanlde f; // 실제 폰트 자원
};
아래 처럼 사용 가능
void changeFontSize(FontHandle f, int newSize);
Font f(getFont());
int newSize;
...
changeFontSize(f.get(), newSize); // 명시적으로 바꾼 후 전달.
하지만 변환할 때마다 get()함수를 호출해야 하는 귀찮은 점이 존재함
그래서 암시적 변환 함수 제공해 보자.
class Font {
public:
...
operator FontHanlde() const // 암시적 변환함수
{ return f; }
...
};
아래 처럼 사용 가능
Font f(getFont());
int newFontSize;
...
changeFontSize(f, newFontSize);
하지만 아래와 같은 부작용 발생이 가능하다.
Font f1(getFont());
...
FontHandle f2 = f1; // 원래는 Font 객체를 복사하는 것이었는데
// f1이 FontHanlde로 변환되고 복사되어 버림.
위 코드는 객체인 f1과 f2가 동시에 자원을 물고 있는 경우가 된다. 좋지 않은 코드가 된다.
3. RAII 클래스를 실제 자원으로 바꾸는 방법을 명시적으로 해야 하나 암시적으로 해야 하나?
RAII 클래스만의 특정한 용도와 사용 환경에 따라 달라진다. 다만 암시적 변환의 지원보다는 명시적 변환 방법이 더 좋은 경우가 많다.
4. RAII 클래스에서 자원 접근 함수를 열어 주는 설계가 캡슐화에 위배되는가?
그렇지 않다. 별로 좋은 모습은 아니지만, RAII 클래스의 목적은 자원의 캡슐화가 목적이 아니다. 자원의 해제가 가장 중요한 목적이다.
5. 자원의 엄격한 캡슐화와 느슨한 캡슐화의 예는?
shared_ptr이 대표적인데, 참조 카운팅 매커니즘은 모두 캡슐화하고 있지만, 관리하는 포인터를 쉽게 접근할 수 있는 통로도 동시에 제공하고 있다.
정리
- 실제 자원을 직접 접근해야 하는 기존 API들도 많기 때문에, RAII 클래스를 만들 때는 그 클래스가 관리하는 자원을 얻을 수 있는 방법을 열어 주어야 한다.
- 자원 접근은 명시적 변환 혹은 암시적 변환을 통해 가능하다. 안전성만 따지면 명시적 변환이 대체저으로 더 낫지만, 고객 편의성을 놓고 보면 암시적 변환이 괜찮다.