사용자 도구

사이트 도구


kb:structuredexceptionvscppexception

Structured Exception vs C++ Exception

SE(Structured Exception)과 CE(C++ Exception)을 일관된 방법으로 사용하기

무엇이 문제인가?

SE를 CE와 혼용해서 사용하기 위해서는 대충 아래와 같은 클래스를 만들어 사용해야한다.

#ifndef INCLUDED_SEEXCEPTION_H
#define INCLUDED_SEEXCEPTION_H
 
#include <eh.h>
 
// Maps a Win32 structured exception to a C++ exception.
// Useful to trap things like access violations.
class SeException 
{
private:
    unsigned int m_se;
 
public:
    SeException(unsigned int n) : m_se(n) {}
    ~SeException() {}
 
public:
    unsigned int GetSeNumber() { return m_se; }
 
    // Call this function to start the mapping
    static void Init() {
        static bool g_Init = false;
        if (!g_Init) {
            _set_se_translator(Translator);
            g_Init = true;
        }
    }
 
private:
    SeException() {}
    SeException( SeException& ) {}
 
    static void Translator( unsigned int u, _EXCEPTION_POINTERS* pExp ) {
        throw SeException(u);
    }
};
 
#endif // INCLUDED_SEEXCEPTION_H

위 클래스에서 핵심이 되는 것은 _set_se_translator 함수다. 이 함수만 제대로 호출하면 try-catch 구문에서 SE를 잡아낼 수 있다.

문제가 되는 것은 VisualCpp의 관련 세팅(구성 속성 > C/C++ > C++ 예외 처리 가능)이 기본적으로 동기 예외 처리 모델(Synchronous Exception Model, /EHs)이라는 점이다. try-catch 구문에서 SE를 잡아내기 위해서는, 즉 _set_se_translator 함수를 사용하기 위해서는 비동기 예외 처리 모델(Asynchronous Exception Model, /EHa)을 사용해야한다.

  • 비동기 예외 처리 모델 – 어떤 명령(instruction)이라도 예외를 발생시킬 수 있다.
  • 동기 예외 처리 모델 – throw 구문 안에서만 예외를 발생시킬 수 있다. 그러므로 컴파일러가 좀더 많은 최적화를 수행할 수 있다. 기본 옵션이다.

비동기 모델을 사용하지 않을 경우, 스택 언와인드가 일어났을 때, 객체의 소멸자가 호출되지 않을 수 있으며, 예외 자체도 가장 가까운 try-catch 블록에서 잡히지 않을 수 있다. 아래의 최적화 관련 문제에서도 나오지만, 이런 문제는 주로 릴리즈 빌드에서 일어나는 모양이다. 최적화하지 않아야할 것을 최적화해버리는 것이니깐.

비동기 모델을 사용할 때 또 생각해 봐야할 것은 최적화 관련 문제다. 동기 모델과는 달리, 비동기 모델에서는 컴파일러가 코드의 흐름을 예측할 수 없기 때문에 최적화 기능 중에 많은 것이 빠지게 된다. 프로그램의 성능을 떨어뜨리면서까지 둘 모두를 사용할 필요가 있는가에 대해서 생각해 보라.

주의할 점

  • 비동기 예외 처리 모델은 콤보 박스를 이용해 선택할 수 없으므로, “구성 속성 > C/C++ > C++ 예외 처리 가능 플래그”를 “아니오”로 바꾸고, “구성 속성 > C/C++ > 명령줄”에서 추가 옵션에다 직접 입력해 줘야한다.
  • 다중 스레드 환경에서는 스레드를 생성할 때마다 그 스레드 안에서 _set_se_translator 함수를 호출해줘야한다. 예외 형식 변경이 각 스레드별로 관리되기 때문이다.

링크

kb/structuredexceptionvscppexception.txt · 마지막으로 수정됨: 2014/11/07 10:43 (바깥 편집)