在结构化异常的情况下堆栈展开

时间:2009-03-06 06:14:00

标签: c++ mfc exception-handling stack seh

此问题更清晰地说明了here所描述的问题。我做了一些调查,发现堆栈展开不会发生在下面的代码中:

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 个答案:

答案 0 :(得分:7)

在未定义行为的情况下,C ++标准不提供任何帮助。即使MS确实如此。这是一个特定于平台的东西 - 所以要小心。一些此类浮点异常转向Win32异常,您可以尝试使用_set_se_translator()捕获。问题是你可以捕获Win32异常,但是你的堆栈将无法正确解开。至少那不是你可以打赌你的生活。其中就是练习无效。

  

更新:故意抛出异常以检查堆栈展开。问题是为什么Wrapper类的析构函数没有被调用。 - Naveen

如果是这种情况 - 请不要这样做。抛出异常的方法比通过未定义的行为更好。

E.g:

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不是任何对象的有效地址(这由标准保证)。

答案 1 :(得分:4)

如果要使用SEH,则必须使用_set_se_translator函数和/ EHa编译器选项。

答案 2 :(得分:2)

因为C ++常规异常不能处理这种异常,所以你必须使用SEH,它对应用程序一无所知并且不会解开。

答案 3 :(得分:0)

这是未定义的行为:

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");
}