구조화 된 예외의 경우 쌓기
-
03-07-2019 - |
문제
이 질문은 설명 된 문제에 대한 명확성을 제공합니다 여기. 나는 더 많은 조사를했고 스택 풀기가 다음 코드에서 일어나지 않는다는 것을 발견했습니다.
class One
{
public:
int x ;
};
class Wrapper
{
public:
Wrapper(CString csText):mcsText(csText)
{
CString csTempText;
csTempText.Format("Wrapper constructor :: %s\n", mcsText);
OutputDebugString(csTempText);
}
~Wrapper()
{
CString csTempText;
csTempText.Format("Wrapper destructor :: %s\n", mcsText);
OutputDebugString(csTempText);
}
CString mcsText;
};
class Test
{
public:
void notifyError()
{
try
{
int x = 10;
}
catch(...) {}
}
void OnRecvBuffer()
{
try
{
Wrapper a("AddRef");
One* p = NULL;
p->x = 10;
}
catch(...)
{
notifyError();
}
}
};
int main()
{
Test* pTest = new Test;
pTest->OnRecvBuffer();
OutputDebugString("Test");
}
VC6 SP5 컴파일러를 사용 하여이 코드를 컴파일했으며 출력은 "래퍼 생성자 :: addRef !!!"입니다. (즉, 스택에 구성된 래퍼 객체의 파괴자는 호출되지 않습니다. 이것이 예상되는 동작입니까?
해결책
SEH를 사용하려면 _SET_SE_TRANSLATOR 기능 및 /EHA 컴파일러 옵션을 사용해야합니다.
다른 팁
C ++ 표준은 정의되지 않은 동작의 경우 작업 할 것이 없습니다. MS가 그렇게하더라도. 그것은 플랫폼 구체적인 것입니다. 따라서 조심하십시오. 그러한 부동 소수점 예외는 당신이 잡을 수있는 Win32 예외로 바뀝니다. _set_se_translator()
. 문제는 Win32 예외를 포착 할 수 있지만 스택은 제대로 풀리지 않습니다. 적어도 그것은 당신이 당신의 삶에 걸릴 수있는 것이 아닙니다. 여기서 운동의 무익함이 있습니다.
업데이트 : 스택 풀기를 확인하기 위해 의도적으로 예외가 발생합니다. 문제는 래퍼 클래스의 파괴자가 호출되지 않는 이유입니다. - Naveen
이것이 사실이라면 -하지 마십시오. 정의되지 않은 행동보다 예외를 던지는 더 좋은 방법이 있습니다.
예 :
void OnRecvBuffer()
{
try
{
Wrapper a("AddRef");
throw 42; // this'll throw an exception without invoking UB
}
catch(...)
{
notifyError();
}
}
널 포인터를 피할 수는 없습니다. 당신은 여기에서 정의되지 않은 행동을 호출하고 있습니다.
One* p = NULL;
p->x = 10;
그 라인 후 모든 베팅은 꺼져 있습니다 ~할 수 있었다 우리 모두를 죽였습니다;)
p
A에 대한 포인터입니다 One
물체. an의 주소를 포함해야합니다 One
물체. 당신은 그것을 0으로 초기화했습니다 - 주소 0에는 객체가 없습니다. 0은 어떤 객체에 대한 유효한 주소가 아닙니다 (이것은 표준에 따라 guranteed).
C ++ 일반 예외는 이러한 종류의 예외를 처리하지 않기 때문에 앱에 대해 알지 못하고 긴장을 풀지 않는 SEH를 사용해야합니다.
이것은 정의되지 않은 행동입니다.
One* p = NULL;
p->x = 10;
이 시점에서 응용 프로그램은 스택을 풀지 않고 자유롭게 충돌 할 수 있습니다.
스택 풀기를 테스트하려면 다음과 같이 바꾸십시오.
throw 42; // Life the Universe and Everything thrown away
모든 OBJCT를 동적으로 할당해서는 안됩니다. 이것은 Java가 아닌 C ++입니다!
int main()
{
Test pTest; // Note the lack of new!
pTest.OnRecvBuffer();
OutputDebugString("Test");
}