2014-01-25 3 views
1

이전에 보지 못했던 아주 이상한 행동을 발견했습니다. 복잡한 VS2005 C++ 프로젝트에서 일하고 있습니다.예외가 발생했을 때 소멸자가 실행되지 않음 (스택을 해제하지 않음)

class Tester 
{ 
public: 
    Tester() 
    { 
     TRACE("Construct Tester"); 
    } 
    ~Tester() 
    { 
     TRACE("~Destruct Tester"); 
    } 
}; 

void Thrower() 
{ 
    Tester X; 
    throw std::exception("Booom"); 
} 

Thrower()을 호출하면 Trace output에서 무엇을 기대합니까? 테스터가 생성 된 후 스택이 풀렸을 때 파괴됩니까?

적어도 나는 그것을 기대하지만 테스터의 소멸자는 결코 호출되지 않는다!

불가능!!!?!?!

Visual Studio의 버그입니까?

많이 찾았지만 Stackoverflow조차 찾지 못했습니다. 답변을 찾았습니다.

답변

1

무엇이 잘못되었는지를 알아 내는데 하루 종일 걸렸습니다.

이제 내가하는 일을 조금 더 설명해야합니다. LIB 파일로 컴파일되는 C++ 코드가 있습니다. 위의 코드 (Tester and Thrower)는이 일반 C++ LIB 파일에 있습니다.

그리고이 LIB 파일과 링크 된 Managed C++ DLL로 컴파일되는 또 다른 C++ 코드가 있습니다. 그래서 결국 두 코드는 같은 DLL에 있습니다.

ManagedWrapper() 
{ 
    try 
    { 
     Thrower(); 
    } 
    catch (std::exception& e) 
    { 
     throw new System::Exception(e.what()); 
    } 
} 

이 수행 하지 작업 :이처럼 LIB 파일의 코드를 호출 래퍼 함수를 ​​처리했다. 이 코드를 사용하면 닫히지 않은 메모리 누수와 네트워크 소켓이 있습니다. Thrower의 스택이 해제되지 않습니다.

이유는 스택 풀기가 catch에 도달하기 전에 수행되지 않기 때문입니다. 그러나 잡기가 던져 놓는 것보다 다른 라이브러리에 앉을 때 스택은 풀리지 않습니다. DLL은 LIB 파일에서 스택을 푸는 방법을 알지 못합니다. (둘 다 같은 DLL에 마지막으로 컴파일되었지만 !!)

그러나 나는 매우 간단한 해결책을 발견했습니다.

LIB 파일에서 ManagedWrapper()와 Thrower() 사이에 중간 기능을 추가해야했습니다. 코드는 바보 보이지만, 문제를 해결 :

Catcher() 
{ 
    try 
    { 
     Thrower(); 
    } 
    catch(...) // unwind HERE 
    { 
     throw; 
    } 
} 

중요한 것은이 포수는 예외가 발생하는 LIB 파일에 앉아 있어야한다는 것입니다. 예외가 catch되면 스택이 해제되고 예외가 관리되는 래퍼에 다시 throw됩니다.

때로는 어리석은 코드가 매우 지능적입니다!

요약 : 예외가 throw 된 동일한 라이브러리에서 항상 예외를 발견해야한다는 것을 잊지 마십시오. 라이브러리 경계를 넘어서게되면 심각한 문제가 발생합니다.

+0

저는 언어 변호사로부터 C++ 표준이 허용하는지 여부에 관해 의견을 듣고 싶습니다. 구현에 버그가 무엇인지 설명하고있는 것 같습니다. – WilliamKF

+0

Visual Studio의 버그 인 경우 인터넷에 정보가 있어야합니다. 그러나 나는 아무것도 찾을 수 없었다. 하지만 어쩌면 당신이 옳을 수도 있습니다. – Elmue

관련 문제