PrettyMenu 클래스
class PrettyMenu
{
public:
...
void changeBackground(istream& imgSrc); // 배경 그림을 바꾸는 멤버 함수
...
private:
Mutex mutex;
Image* bgImage; // 현재 배경 그림
int imageChanges; // 배경 그림이 바뀐 횟수
};
void PrettyMenu::changeBackground(istream& imgSrc)
{
Lock(&mutex); // 뮤텍스 획득
delete bgImage;
++imageChanges;
bgImage = new Image(imgSrc);
unlock(&mutex); // 뮤텍스 해제
}
여기서 changeBackground
함수는 예외 안정성을 확보하지 못했다.
예외 안정성을 확보하는 두 가지 조건
changeBackground
가 예외 안정성을 확보하지 못한 이유
new Image(imgSrc)
에서 예외를 던지면 unlock
함수가 호출되지 않아 뮤텍스가 계속 잡힌 상태로 남게 된다.new Image(imgSrc)
에서 예외를 던졌을 때 bgImage
는 이미 삭제된 후며, 새 그림으로 변경되지 않았음에도 imageChanges
는 증가한다.자원 누출 문제 해결 방법
void PrettyMenu::changeBackground(istream& imgSrc)
{
Lock ml(&mutex); // 항목 14 참고. 뮤텍스가 필요 없어질 시점에 바로 해제해주는 객체
delete bgImage;
++imageChanges;
bgImagd = new Image(imgSrc);
}
자원 누출 문제는 객체를 통해 자원 관리를 전담케 하고(항목 13), 자원이 필요없어질 시점에 해제(항목 14)하면 해결할 수 있다.
예외 안정성을 갖춘 함수는 아래 세가지 보장 중 하나를 반드시 제공한다.
따라서 어떤 예외 안정성을 보장할 것인지 선택해야 한다.
함수 동작 중에 예외 발생 시, 모든 것들을 유효한 상태로 유지한다는 보장이다. (=클래스 불변속성을 만족)
프로그램의 상태가 정확히 어떠한지 예측이 안된다는 단점이 있다.
함수 동작 중에 예외 발생 시, 프로그램 상태를 절대로 변경하지 않겠다는 보장이다. (=원자적인 동작)
예측할 수 있는 프로그램의 상태가 단 두가지이다. (성공적으로 실행을 마친 상태 or 함수가 호출될 때의 상태)
예외를 절대로 던지지 않겠다는 보장으로, 약속한 동작은 언제나 끝까지 완수한다.
int doSomething() throw();
위 함수는 예외불가 보장을 제공하지 않는다.
여기서 throw()
는 doSomething
에서 지정되지 않은 예외가 발생했을 경우, terminate
함수가 호출된다는 의미이다.
Exception specifications (throw, noexcept) (C++)
(본 책에서는 예외가 발생하면 unexpected 함수가 호출된다고 하는데, 이는 C++14까지만 해당된다.
C++17 표준 및 std:++17 이상에서는 std::terminate
가 호출된다.)
changeBackground
함수에 강력한 보장을 제공해보자.
bgImage
멤버 타입을 자원관리 전담용 포인터로 변경Image*
-> shared_ptr<Image>
changeBackground
함수 내 코드 재배치imageChanges
증가
class PrettyMenu
{
...
shared_ptr<Image> bgImage;
...
};
void PrettyMenu::changeBackground(istream& imgSrc)
{
Lock ml(&mutex);
bgImage.reset(new Image(imgSrc));
++imageChanges;
}
이전 코드와 비교했을 때 장점
delete
하지 않아도 됨delete
연산자가 reset
함수 내에 있음new Image(imgSrc)
가 제대로 생성되어야 reset
함수가 호출됨shared_ptr
를 사용하면서 함수의 길이가 줄어듦// 복사 후 맞바꾸기 방법 작성 예정
예외 안정성 확보하는 방법
1. 자원 관리용 객체 사용
2. 새로 만드는 함수에 어떤 예외 안정성을 보장할 지 결정하고 문서로 남김
정리
- 예외 안정성: 기본적인 보장, 강력한 보장, 예외 금지 보장
- 예외 안정성을 갖춘 함수는 예외가 발생해도 자원을 누출시키지 않고 자료구조를 더럽힌 채로 두지 않는다.
- 강력한 예외 안정성 보장은 '복사 후 맞바꾸기'방법으로 보장 구현 가능
- 그러나 모든 함수에 대해 실용적이지는 않다.
- 어떤 함수가 제공하는 예외 안정성 보장의 강도는 그 함수의 내부에서 호출하는 함수가 제공하는 가장 약한 보장이다.