throw · unwind · catch

예외 실행 모델

예외가 던져지면 현재 실행은 중단되고 handler를 찾을 때까지 스택이 되감긴다. 이때 지역 객체 소멸, 객체 불변식, noexcept 경계가 동시에 안전해야 한다.

01

throw site 확정

파일 없음, 파싱 오류, precondition 위반을 구분하고 예외 타입에 context를 싣는다.

throw by value, catch by reference
02

stack unwinding

예외가 지나가는 프레임마다 지역 객체 소멸자가 역순으로 호출되어 파일, 메모리, lock을 닫는다.

destructor는 밖으로 던지지 않는다
03

handler selection

가장 가까운 matching catch가 복구, 변환, 재던지기 중 하나를 수행하고 객체 상태 보장 수준을 지킨다.

catch(...)는 경계 변환에 한정
basic
불변식 유지 실패해도 객체는 파괴 가능하고 다시 사용할 수 있다.
destructor 가능, invariant 유지
strong
커밋 전 상태 유지 실패하면 호출 전 상태로 남긴다.
commit 전 임시 객체와 swap 사용
noexcept
예외 전파 없음 던지면 terminate로 이어질 수 있으므로 내부 호출을 확인해야 한다.
move, destructor, callback 경계
catch
정책 위치 처리할 수 없는 곳에서 잡으면 오류가 숨겨진다.
context 추가 후 rethrow 가능

destructor·invariant·handler 테스트

destructor cleanup 예외 경로에서 직접 close, delete, unlock이 빠질 가능성이 없는가.
class invariant 함수 실패 뒤 객체가 파괴 가능하고 public 함수가 다시 호출 가능한 상태인지 설명할 수 있는가.
typed catch catch가 실제 복구를 하거나 path, errno, 입력 위치 같은 context를 붙여 다시 던지는가.

RAII 전제

std::vector<Record> load_records(std::filesystem::path path) {
    std::ifstream in(path);
    if (!in) throw FileError{};
    return parse_records(in);
}