EC++ 항목 08 - 예외가 소멸자를 떠나지 못하도록 붙들어 놓자


예외가 소멸자를 떠나지 못하도록 붙들어 놓자

이것만은 잊지말자 1

소멸자에서는 예외가 빠져나가서는 안됩니다.
소멸자 안에서 호출된 함수가 예외를 던질 가능성이 있다면,
소멸자에서 삼켜 버리던지, 프로그램을 끝내든지 해야 된다.

stack unwinding

소멸자 밖으로 예외가 전파되면 가장 문제가 되는 건 stack unwinding 관련된 문제다.
일반적으로 예외가 발생하면, catch 문까지 stack이 되감기면서 로컬 변수들의 소멸자를 호출한다.
소멸자에서 다시 한 번 예외가 발생하면 프로그램은 무조건 crash 가 발생하게 된다.

프로그램 종료

DBConn::~DBConn
{
    try{ db.close(); }
    catch (...)
    {
        close 로그 작성
        std::abort();
    }
}

소멸자에서 삼키기

참고로 예외를 삼키는 방법을 사용하려면, 예외 발생과 상관없이 프로그램이 정상 동작 할 수 있도록 reliable 해야 한다.

DBConn::~DBConn
{
    try{ db.close(); }
    catch (...)
    {
        close 로그 작성
    }
}

이것만은 잊지말자 2

어떤 예외에 대해 사용자가 반응해야 한다면,
해당 연산을 제공하는 함수는 보통 함수여야 한다.

위에서 봤던 예외 삼키기, 프로그램 종료하기 보다 더 좋은 전략은 다음과 같다.
바로 - 예외에 대처할 기회를 사용자에게 준다.

DB를 닫는 close 함수를 사용자에게 제공하고,
소멸자에서는 DB가 열려있는 경우에만 close를 호출한다.

이를 통해 사용자에게 에러를 처리할 수 있는 기회를 줄 수 있다.

이 방법의 핵심은 예외가 발생할 가능성이 있다면, 그 예외는 소멸자가 아닌 일반 함수에서 비롯되어야 한다는 것이다.
아래 코드에서 소멸자에서 예외가 발생하는 것보단 사용자가 close() 함수를 호출 했을 때 예외가 발생하는 게 더 나은 설계이다.

void close()
{
    db.close();
    close = true;
}
DBConn::~DBConn
{
    if( !closed)
    {
        try{
            db.close();
        }
        catch (..){
            close 로그 작성
        }
    }
}





© 2017. by devan

Powered by devan