4

この質問は、ここで説明されている問題をより明確にします。さらに調査を行ったところ、次のコードではスタックの巻き戻しが行われていないことがわかりました。

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 コンパイラのバグですか?この場合、スタックの巻き戻しが発生するようにコンパイラ フラグを使用できますか?

4

4 に答える 4

7

C++ 標準は、未定義の動作の場合に動作するものを何も提供しません。MSがそうであっても。これはプラットフォーム固有のものですので、注意してください。このような浮動小数点例外の一部は Win32 例外に変換され、_set_se_translator(). 問題は、Win32 例外をキャッチできるが、スタックが適切にアンワインドされないことです。少なくとも人生を賭けるほどのものではない。練習の無益さはそこにあります。

更新: 例外は、スタックの巻き戻しをチェックするために意図的にスローされます。問題は、Wrapper クラスのデストラクタが呼び出されない理由です。– ナヴィーン

これが事実であるなら、それをしないでください。Undefined Behavior を使用するよりも、例外をスローするより良い方法があります。

例えば:

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;

その行の後、すべての賭けはオフになり、あなたは私たち全員を殺すことができた ;)

pOneオブジェクトへのポインタです。オブジェクトのアドレスが含まれている必要がありOneます。0 に初期化しました -- アドレス 0 にオブジェクトはありません。0 はどのオブジェクトに対しても有効なアドレスではありません (これは標準で保証されています)。

于 2009-03-06T06:24:38.033 に答える
4

SEH を使用する場合は、_set_se_translator 関数と /EHa コンパイラ オプションを使用する必要があります。

于 2009-03-06T06:41:55.140 に答える
2

C++ の通常の例外はこの種の例外を処理しないため、アプリについて何も知らず、巻き戻しを行わない SEH を使用する必要があります。

于 2009-03-06T06:30:23.200 に答える