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 类的析构函数没有被调用。– 纳文

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

例如:

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

于 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 回答
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");
}
于 2009-03-06T08:35:18.673 回答