0

我最近开始从 C# 背景开始学习 C++。我的问题是处理异常的方式。

如果我有一个nullptr地方,导致从一个禁止的位置读取,那么我会在 VS 中得到一个漂亮的调用堆栈,如下所示:

调用栈

但是,如果我抛出我自己的异常,或者断言失败,那么我就不会得到任何关于出了什么问题的线索。VS 只是显示一个错误窗口:

在此处输入图像描述

答:这对我来说有点不舒服,因为在 C# 中我会在这两种情况下获得堆栈跟踪。有没有办法打印堆栈跟踪?或者有没有VS的插件来实现这个功能?

B:为什么 AccessViolationException 与我们自己抛出的异常不同?为什么我们没有断言失败的堆栈跟踪?

C:创建我自己的断言函数会有多糟糕,当断言失败时会导致 AccessViolationException?

EDIT1:是的,我应该更仔细地阅读该消息框,而不是立即单击中止。我的错。

4

1 回答 1

2

为什么 AccessViolationException 与我们自己抛出的异常不同?

因为 AV 是特殊的,所以它是由处理器本身触发的异常。当它发出不再能够执行代码的信号时引发。这是你可以想象的最糟糕的事故。从 AV 中恢复非常非常困难,通常不应尝试。您无法再推断程序的状态,除了原始指令地址之外,您不知道它在哪里死亡。

捕获和处理 AV 在技术上是可行的,您必须使用结构化异常处理。它需要在 MSVC++ 中使用非标准的 __try 和 __except 关键字。但是您不应该这样做,因为处理异常还需要您将程序的状态恢复到运行失败代码之前的状态。由于您无法再推断该状态,因此不可能可靠地执行,您不知道异常跳过了哪些代码。

您可以以某种合理的方式关闭程序,它需要使用 SetUnhandledExceptionFilter() winapi 函数。相当于 C# 中的 AppDomain.UnhandledException。当然,所有这些都完全是非标准的 C++。C++ 标准规定,符合标准的 C++ 程序永远不应调用未定义的行为,并且没有指定无论如何应该发生什么。

否则,这是靠近金属编程的直接后果。托管代码中有很多对策可以防止程序进入这样的状态。这些对策不是免费的,原生 C++ 关心的是让代码尽可能快地运行。失去诊断是这种权衡的一部分。不要调用未定义的行为。

于 2013-09-22T10:33:12.723 回答