此问题为此处描述的问题提供了更清晰的信息.我做了一些调查,发现堆栈展开不会发生在下面的代码中:
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编译器的错误?我可以使用一些编译器标志,以便在这种情况下发生堆栈展开吗?
在未定义行为的情况下,C++标准不提供任何可用的功能.即使MS确实如此.这是一个特定于平台的东西 - 所以要小心.一些这样的浮点异常转向Win32异常,您可以尝试捕获它们_set_se_translator()
.问题是你可以捕获Win32异常,但是你的堆栈将无法正确解开.至少那不是你可以打赌你的生活.其中就是练习徒劳无功.
更新:有意抛出异常以检查堆栈展开.问题是为什么Wrapper类的析构函数没有被调用. - Naveen
如果是这种情况 - 不要这样做.抛出异常的方法比通过未定义的行为更好.
例如:
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不是任何对象的有效地址(这由标准保证).