일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- more effective c++
- Effective c++
- virtual function
- 영화 리뷰
- 게임
- resource management class
- 비교 함수 객체
- lua
- 티스토리챌린지
- 루아
- operator new
- UE4
- 예외
- 오블완
- exception
- effective stl
- 메타테이블
- 스마트 포인터
- 다형성
- c++
- 암시적 변환
- 참조자
- 상속
- Vector
- 언리얼
- Smart Pointer
- reference
- 영화
- implicit conversion
- 반복자
Archives
- Today
- Total
스토리텔링 개발자
[More Effective C++] 9. 자원 관리 객체(RAII) 본문
728x90
항목 9 : 리소스 누수를 피하는 방법의 정공은 소멸자이다.
지역 리소스에 대한 포인터
- 지역 리소스(스택에서 생긴 리소스)를 조작할 때, 포인터는 부적절할 수 있다.
- 소멸자가 불리지 않는 상황이 발생할 수 있기 때문이다.
- 즉, 리소스 누수가 발생할 수 있다는 뜻이다.
class ALA
{
public:
virtual void processAdoption() = 0;
...
};
class Puppy : public ALA
{
public:
virtual void processAdoption();
...
};
class Kitten : public ALA
{
public:
virtual void processAdoption();
...
};
// s로부터 동물 정보를 읽어서
// 적절한 타입의 객체를 동적할당 후
// 포인터 반환
ALA* readALA(istream& s) { ... }
void processAdoptions(istream& dataSource)
{
while(dataSource)
{
ALA* pa = readALA(dataSource); // 객체 생성
pa->processAdoption(); // 가상 함수 처리
delete pa; // 객체 삭제
}
}
- 헌데 위의 로직에서 '가상 함수 처리'(pa->processAdoption()) 중 예외가 발생하면?
- delete가 불리지 않으면서 리소스 누수가 발생한다.
- 예외를 처리
void processAdoptions(istream& dataSource)
{
while(dataSource)
{
ALA* pa = readALA(dataSource);
try
{
pa->processAdoption();
}
catch(...)
{
delete pa; // 객체 삭제
throw; // 예외 전파
}
delete pa; // 객체 삭제
}
}
- 문제점
- try - catch 블록으로 코드가 복잡해진다.
- 코드 중복이 발생한다.( delete pa )
예외 발생 시 소멸자를 반드시 호출하는 방법
- 포인터 대신 포인터처럼 동작하는 객체, 즉 스마트 포인터를 사용한다.(항목 28 참조)
- 자신의 유효범위(scope)를 벗어나면 자신이 가리키는 메모리를 삭제한다.
template<typename T>
class auto_ptr
{
public:
auto_ptr(T* p = 0) : ptr(p) {}
~auto_ptr() { delete ptr; }
private:
T* ptr;
};
void processAdoptions(istream& dataSource)
{
while(dataSource)
{
auto_ptr<ALA> pa(readALA(dataSource)); // 스마트 포인터 사용으로 대체
pa->processAdoption();
]
}
- 다만 이는 단일 객체에 대해서만 유효하며, 배열 포인터의 경우 다른 방도가 필요하다.
- 스마트 포인터가 단일 객체 형태의 delete를 사용하기 때문이다. (항목 8 참조)
- 배열 포인터에 대해 auto_ptr처럼 동작하는 클래스가 필요하다면 만들어야 한다.
- 하지만 vector 같은 STL 컨테이너를 쓰는 것이 훨씬 나은 선택이다.
자원 관리 객체를 사용하는 다른 예
void displayInfo(const Information& info)
{
WINDOW_HANDLE w(createWindow()); // 윈도우 리소스 획득
w를 핸들로 하는 윈도우에 정보를 표시한다;
destroyWindow(w); // 윈도우 리소스 해제
}
- 리소스가 포인터는 아니지만, 윈도우 리소스가 해제되지 않으면 리소스 누수가 발생한다.
- 자원 관리 객체로 자원 획득 / 해제를 컨트롤하도록 수정한다.
class WindowHandle
{
public:
WindowHandle(WINDOW_HANDLE handle) : w(handle) {}
~WindowHandle() { destroyWindow(w); }
operator WINDOW_HANDLE() { return w; } // WINDOW_HANDLE로의 암시적 변환 지원
private:
WINDOW_HANDLE w;
// 복사 생성자 자동 생성 막기(항목 28 참조)
WindowHandle(const WindowHandle&);
WindowHandle& oepratr=(const WindowHandle&);
};
void displayInfo(const Information& info)
{
WindowHandle w(createWindow());
w를 핸들로 하는 윈도우에 정보를 표시한다;
}
- 암시적 변환 지원을 하고 있으나, 일반적으로는 좋지 않은 생각이다.(항목 5 참조)
- 복사 동작을 막아뒀다.(EC++ 항목 14 참조)
참고
728x90
'개발 > More Effective C++' 카테고리의 다른 글
[More Effective C++] 11. 소멸자 예외 처리 (0) | 2024.08.13 |
---|---|
[More Effective C++] 10. 생성자 예외 처리 (0) | 2024.08.12 |
[More Effective C++] 8. new / delete 연산자와 operator new / delete (0) | 2024.08.08 |
[More Effective C++] 7. operator&& / operator|| / operator, (0) | 2024.08.07 |
[More Effective C++] 6. operator++ / operator-- (0) | 2024.08.06 |
Comments