[英]Stack unwinding in case of structured exceptions
這個問題更清楚地說明了這里描述的問題。 我做了更多調查,發現堆棧展開沒有發生在以下代碼中:
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 編譯器編譯了這段代碼,output 是“包裝器構造函數::AddRef ...”(即?沒有調用在堆棧上構造的包裝器 object 的析構函數?這是預期的行為嗎?還是它VC 編譯器的錯誤?我可以使用一些編譯器標志,以便在這種情況下發生堆棧展開嗎?
C++ 標准沒有提供任何可用於未定義行為的情況。 即使 MS 有。 這是特定於平台的事情——所以要小心。 一些這樣的浮點異常被轉換為 Win32 異常,您可以嘗試使用_set_se_translator()
來捕獲這些異常。 問題是您可以捕獲 Win32 異常,但是您的堆棧將無法正確展開。 至少這不是你可以賭上生命的事情。 這就是練習的徒勞。
更新:故意拋出異常以檢查堆棧展開。 問題是為什么 Wrapper 類的析構函數沒有被調用。 – 納文
如果是這種情況 - 不要這樣做。 有比通過未定義行為更好的方法來引發異常。
例如:
void OnRecvBuffer()
{
try
{
Wrapper a("AddRef");
throw 42; // this'll throw an exception without invoking UB
}
catch(...)
{
notifyError();
}
}
您不能取消引用 NULL 指針。 您在這里調用未定義的行為:
One* p = NULL;
p->x = 10;
在那條線之后,所有的賭注都被取消了,你本可以殺了我們所有人;)
p
是指向One
object 的指針。 它應該包含One
object 的地址。 您已將其初始化為 0 - 地址 0 處沒有 object。0 不是任何 object 的有效地址(這是由標准保證的)。
如果要使用 SEH,則必須使用 _set_se_translator function 和 /EHa 編譯器選項。
因為 C++ 常規異常不處理此類異常,所以您必須使用對應用程序一無所知且不會展開的 SEH。
這是未定義的行為:
One* p = NULL;
p->x = 10;
此時,應用程序可以在不展開堆棧的情況下自由崩潰。
如果要測試堆棧展開,請將其替換為:
throw 42; // Life the Universe and Everything thrown away
您不應該動態分配所有對象,這是 C++ 而不是 Java!
int main()
{
Test pTest; // Note the lack of new!
pTest.OnRecvBuffer();
OutputDebugString("Test");
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.