構造化例外の場合のスタックの巻き戻し
-
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コンパイラを使用してこのコードをコンパイルしましたが、出力は" Wrapper constructor :: AddRef !!!"です。 (つまり、スタック上に構築されたラッパーオブジェクトのデストラクタは呼び出されません。これは予想される動作ですか?またはVCコンパイラのバグですか?この場合スタックの巻き戻しが発生するようにいくつかのコンパイラフラグを使用できますか? >
解決
SEHを使用する場合は、_set_se_translator関数と/ EHaコンパイラオプションを使用する必要があります。
他のヒント
C ++標準は、未定義の動作の場合に動作するものを提供しません。 MSが行っても。これはプラットフォーム固有のことですので、注意してください。このような浮動小数点例外の一部は、 _set_se_translator()
でキャッチしようとするWin32例外に変換されます。問題は、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
オブジェクトへのポインターです。 One
オブジェクトのアドレスを含める必要があります。これを0に初期化しました。アドレス0にオブジェクトはありません。0はオブジェクトの有効なアドレスではありません(これは標準で保証されています)。
C ++の通常の例外はこの種の例外を処理しないため、アプリについて何も知らず、巻き戻さないSEHを使用する必要があります。
これは未定義の動作です:
One* p = NULL;
p->x = 10;
この時点で、アプリケーションはスタックを巻き戻さずに自由にクラッシュします。
スタックの巻き戻しをテストする場合は、これを次のように置き換えます。
throw 42; // Life the Universe and Everything thrown away
すべてのオブジェクトを動的に割り当てるべきではありません。これはJavaではなくC ++です。
int main()
{
Test pTest; // Note the lack of new!
pTest.OnRecvBuffer();
OutputDebugString("Test");
}