본문 바로가기

Library/C/C++

예외 지정 기능은 신중히 사용하라

예외 지정(exception specification) 기능은 함수의 인터페이스에 발생 가능한 예외 종류를 명확하게 지정할 수 있다. 그러나, 기존 코드와의 호환성 때문에 이 기능은 신중하게 사용해야 한다. 즉, 다음과 같은 경우를 생각할 수 있다.


void foo() throw(exception)
{
    ....
    bar();
    ....
}


bar() 함수가 foo() 함수 내부 정의에 사용되고 있는데, C++는 코드 호환성 때문에 bar()가 예외 지정 기능을 사용하지 않았더라도 이 코드는 컴파일이 가능하다. 만약 bar()가 exception 이외의 예외를 던진다면, 이 프로그램은 즉시 unexpected 함수를 호출하며, 대부분 abort()에 의해 프로그램이 종료된다. 즉, 예외 지정 선언은 주의 깊게 사용하지 않을 경우 다음과 같은 코드에서 문제를 일으킬 수 있다.


Destructor::~Destructor()
{
    try { Cleanup(); }
    catch(...) {}
}


보통의 경우라면, Cleanup() 함수에 의해 필요한 정리 작업이 수행되며, 어떤 종류의 예외가 발생하더라도 최소한 소멸자에서 프로그램이 죽는 일은 발생하지 않는다. 그러나, Cleanup()에 예외 지정 기능을 사용했고, 함수 정의에서 이런저런 잡다한 정리 함수들이 추가되는 상황을 생각해보자.


void Cleanup() throw(exception)
{
    ....
    ReleaseMutex();
    ....
    ReleaseMemory();
}


만약, Release...() 종류의 함수들이 exception 타입이 아닌 다른 예외을 던진다면 소멸자에서 애써 만들어놓은 try - catch 블럭이 아무런 도움도 되지 못한다. Cleanup() 함수가 던질 수 있는 예외가 명시적으로 지정되어 있기 때문에, 그 외의 예외가 발생하는 즉시 unexpected 함수가 호출되고 기본 예외 핸들러에 의해 상황이 정리된다. 기본 예외 핸들러를 교체하거나, 다시 try-catch를 사용할 수 있겠지만 과거의 모든 코드들을 여기에 맞춰 재작성할 수 없는 노릇이다.

결국, 예외 지정 기능은 완전한 예외 처리를 구현하는 경우가 아니라면 그 사용에 있어 극도로 신중해야 한다. 예외 지정 기능은 함수 인터페이스를 명확하게 해준다는 장점이 있지만, 예외 지정 기능이 포함된 코드를 과거 코드와 섞어 쓸 경우 한 순간에 모든 예외 안전 장치들을 무용지물로 만들 위험성을 내포하고 있다.