[C++] 항목 15: 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자
카테고리: Cpp
태그: Cpp
이 글은 아래의 책을 자세히 정리한 후, 정리한 글을 GPT에게 요약을 요청하여 작성되었습니다.
이펙티브 C++ 제3판, 스콧 마이어스 저자, 곽용재 번역
📦 3. 자원 관리
👉🏻 항목 15: 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자
shared_ptr<Investment> pInv(createInvestment());
int daysHeld(const Investment *pi);
이렇게 함수 선언과 자원 생성이 돼 있다고 하자.
근데 아래처럼 쓰면?
int days = daysHeld(pInv);
컴파일 에러가 난다.
pInv는 shared_ptr
int days = daysHeld(pInv.get());
shared_ptr에 들어있는 실제 포인터를 꺼내기 위해선 위와 같이 짜야한다.
이때 pInv.get()
과 같은 방식으로 형을 변경하는 방식을
명시적 변환(explicit conversion)이라고 한다.
암시적 변환도 있는데 이는 다음 코드를 보면서 알아보자.
🔃 명시적, 암시적 변환
클래스가 변환 연산자를 제공하면, 암시적 변환(implicit conversion)도 가능하다.
// 아래 코드는 C API에서 가져온 함수
// 실제로 있는 함수는 아닌듯 하다.
// (매개 변수, 구현부 생략됨)
FontHandle getFont();
void releaseFont(FontHandle fh);
// 폰트 API의 일부
void changeFontSize(FontHandle f, int newSize);
// RAII 클래스
class Font {
public:
explicit Font(FontHandle fh) // 자원 획득
: f(fh) {}
~Font() { // 자원 반환
releaseFont(f);
}
FontHandle get() const { return f; } // 명시적 변환
operator FontHandle() const { return f; } // 암시적 변환
private:
FontHandle f;
};
Font 클래스는 FontHandle
이라는 자원을 RAII 방식으로 감싸고 있다.
생성 시 자원을 획득하고, 소멸 시 자원을 해제한다.
🧪 변환 예시
int main() {
Font f(getFont());
int newFontSize;
// *첫번째 상황* : Font f 객체에서 FontHandle 꺼내기
// 명시적 변환
changeFontSize(f.get(), newFontSize);
// 암시적 변환
changeFontSize(f, newFontSize);
변환 연산자 operator FontHandle()
덕분에 암시적으로 변환이 되고 있다.
💣 문제의 상황
// *두번째 상황*: Font f2 = f1
Font f1(getFont());
// 의도는 Font 객체를 복사하는 것
// Font f2 = f1;와 같이 짰어야했다!
FontHandle f2 = f1;
이런 상황을 조심해야한다.
의도는 Font
객체를 복사하고 싶었던 거지만,
실제로는 암시적 변환이 일어나서 FontHandle
만 복사된다.
결과적으로 f1
이 소멸되면 FontHandle
도 해제되는데,
f2
는 이미 해제된 자원을 계속 가리키는 셈이다.
이는 자원 관리 객체의 목적과 상충된다.
🧭 어떤 변환을 쓸 것인가?
RAII 클래스에서 자원을 외부에 노출할 때는 두 가지 방식이 있다:
.get()
처럼 명시적 접근자 제공operator T()
처럼 암시적 변환 연산자 정의
근데 이것은 클래스의 목적에 따라 달라진다.
- 단순한 포장(wrapper) 클래스처럼 쓸 거면 암시적 변환도 괜찮음
- 자원을 명확히 관리하는 책임이 중요하다면, 명시적 변환이 더 안전함
특히, 복사가 오용될 수 있는 자원이라면 암시적 변환은 피하는 게 좋다.
RAII 클래스를 실제 자원으로 바꾸는 방법으로
명시적 변환을 사용할 것인가, 암시적 변환을 사용할 것인가는
→ RAII 클래스의 특정 사용 용도와 사용 환경에 따라 달라진다.
🧐 정리
- RAII 클래스를 만들 때는 그 클래스가 관리하는 자원을 얻을 수 있는 방법을 열어주자.
- 자원 접근은 명시적/암시적 변환을 통해 가능하다.
안정성은 명시적 변환, 고객 편의성은 암시적 변환이 좋다.
댓글남기기