2

我在 C# 项目中重用了一大块非托管 C++ 代码。非托管 C++ 代码封装在托管 C++ 代码层中,该层与 C# 代码交互。现在,非托管 C++ 代码使用 assert(false) 来引发严重错误。由于 assert() 写入 stderr 并且我的项目是一个 GUI 程序,我认为断言打印输出不会出现。我正在考虑用 throw new exception(...) 替换 assert(false),然后在 C# GUI 层捕获并显示异常。我的问题是:

1) 用 exception() 替换 assert() 是个好主意吗?如果不是为什么?

2) 如果在非托管 C++ 代码中引发异常,它们是否会正确传播到托管 C++,然后传播到 C# 代码(堆栈跟踪完整且正确)?

谢谢,

4

1 回答 1

5

1) 用 exception() 替换 assert() 是个好主意吗?如果不是为什么?

assert是一个调试工具。它将在发布版本中评估为无操作,并且不打算用作错误处理工具。在 C++ 中实现基于异常的错误报告系统是很自然的事情。

2) 如果在非托管 C++ 代码中引发异常,它们是否会正确传播到托管 C++,然后传播到 C# 代码(堆栈跟踪完整且正确)?

从非托管代码转换到托管代码时,本机代码中抛出的 C++ 异常将转换为SEHException。C++ 异常可以在本机代码、C++/CLI 互操作层或托管代码中处理。(人类可读)调用堆栈信息在本机代码中不可用。


混合模式环境中异常处理的背景信息:

C++ 异常(在 Microsoft 的 C++ 编译器中实现)以及 CLR 中的异常都建立在 SEH 异常之上。结构化异常处理是 Windows 中内置的一项服务,任何可以与 C 接口的环境都可以使用该服务。共享相同的基础使异常能够无缝地从托管代码传播到非托管代码,反之亦然。

所有 SEH 异常都带有存储在EXCEPTION_RECORD. 该ExceptionAddress成员用作构造堆栈跟踪的入口点。托管程序集包含足够的元数据来构建人类可读的堆栈跟踪。另一方面,本机可执行映像没有。虽然可以生成堆栈跟踪(StackWalk64例如使用 ),但除非相应的调试信息 (.pdb) 可用,否则不会包含符号信息。


堆栈跟踪的替代方案:

虽然堆栈跟踪可能会为您提供一些引发异常的提示,但它不包含任何对调试有用的信息,例如参数和局部变量。另一种方法是编写一个小型转储。MiniDumpWriteDump是一个非常强大的工具,可以让您非常精细地控制应该包含哪些数据。一个很好的介绍可以在Effective Minidumps - Part 1Effective Minidumps - Part 2中找到. Minidump 可以加载到调试器(例如 Visual Studio 或 WinDBG)中并进行分析。使用匹配的调试符号(您应该将其添加到任何版本的源代码控制系统中),您将获得一个非常有效的分析问题的基础设施。根据可用的小型转储信息,您将获得所有线程的调用堆栈、传递给函数的参数、本地内容、加载和卸载的模块等。

于 2013-09-10T18:42:17.853 回答