简体   繁体   English

使用调用堆栈进行C ++ Visual Studio调试

[英]C++ Visual Studio debugging with call stack

I have recently began learning C++ coming from a C# background. 我最近开始学习来自C#背景的C ++。 My problem is with the way exceptions get handled. 我的问题是处理异常的方式。

If I have a nullptr somewhere, resulting in reading from a forbidden location, then I get a nice looking callstack in VS like this: 如果我在某处有一个nullptr ,导致从禁止的位置读取,那么我在VS中得到一个漂亮的callstack,如下所示:

调用堆栈

However if I throw my own exception, or an assertion fails, then I do not get any clue as of what went wrong. 但是,如果我抛出自己的异常,或者断言失败,那么我就不知道出了什么问题。 VS just shows an error window: VS只显示一个错误窗口:

在此输入图像描述

A: This is kind of uncomfortable for me as in C# I would get a stacktrace in both case. 答:这对我来说有点不舒服,因为在C#中我会得到一个堆栈跟踪。 Is there a way to print the stack trace? 有没有办法打印堆栈跟踪? Or is there any plugin for VS to achieve this functionality? 或者是否有任何VS的插件来实现此功能?

B: And why is AccessViolationException different than our own thrown exceptions? B:为什么AccessViolationException与我们自己抛出的异常不同? Why don't we have a stacktrace for assertion failures? 为什么我们没有断言失败的堆栈跟踪?

C: How bad would it be, to create my own assert function, which would cause an AccessViolationException when assertion fails? C:创建自己的断言函数有多糟糕,当断言失败时会导致AccessViolationException?

EDIT1: Yes, I should have read more carefully that messagebox instead of instantly clicking Abort. 编辑1:是的,我应该仔细阅读消息框,而不是立即点击中止。 My bad. 我的错。

And why is AccessViolationException different than our own thrown exceptions? 为什么AccessViolationException与我们自己抛出的异常不同?

Because an AV is special, it is an exception that is triggered by the processor itself. 因为AV是特殊的,所以它是由处理器本身触发的异常。 Raised when it signals that is no longer capable of executing code. 当它发出不再能够执行代码的信号时引发。 That's as bad a mishap as you can possibly imagine. 这就像你可能想象的那样糟糕。 Recovering from an AV is very, very difficult and should in general never be attempted. 从AV中恢复是非常非常困难的,并且通常不应该尝试。 You cannot reason about the state of your program anymore, you don't know where it died beyond just a raw instruction address. 你不能再对你的程序状态进行推理了,你不知道它只是在一个原始的指令地址之外死了。

Catching and handling an AV is technically possible, you have to use Structured Exception Handling. 从技术上讲,捕获和处理AV是必要的,您必须使用结构化异常处理。 It requires using the non-standard __try and __except keywords in MSVC++. 它需要在MSVC ++中使用非标准的__try和__except关键字。 But you should not do that, since handling an exception requires you to also restore the state of your program to the state it had before you ran the code that failed. 但是您不应该这样做,因为处理异常需要您还将程序状态恢复到运行失败代码之前的状态。 Impossible to do reliably since you cannot reason about that state anymore, you don't know what code was skipped by the exception. 无法可靠地执行,因为您无法再解释该状态,您不知道异常跳过了哪些代码。

You can get your program to shutdown in a somewhat reasonable way, it requires using the SetUnhandledExceptionFilter() winapi function. 您可以以一种合理的方式使程序关闭,它需要使用SetUnhandledExceptionFilter()winapi函数。 The equivalent of AppDomain.UnhandledException in C#. 相当于C#中的AppDomain.UnhandledException。 All of this is entirely non-standard C++ of course. 所有这些当然都是完全非标准的C ++。 The C++ standard dictates that a conforming C++ program should never invoke undefined behavior and does not specify what should happen when you do anyway. C ++标准规定,符合标准的C ++程序永远不应该调用未定义的行为,并且不指定当你做什么时应该发生什么。

This is otherwise a direct consequence of programming close to the metal. 否则这是靠近金属编程的直接结果。 There are a lot of counter-measures in managed code to prevent a program from ever getting into a state like this. 托管代码中有很多反措施可以防止程序进入这样的状态。 These counter-measure do not come for free, native C++ cares about making code run as fast as possible. 这些反措施不是免费的,本机C ++关心的是尽可能快地运行代码。 Losing diagnostics is part of that trade-off. 失去诊断是这种权衡的一部分。 Don't invoke undefined behavior. 不要调用未定义的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM