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 1和Effective Minidumps - Part 2中找到. Minidump 可以加载到调试器(例如 Visual Studio 或 WinDBG)中并进行分析。使用匹配的调试符号(您应该将其添加到任何版本的源代码控制系统中),您将获得一个非常有效的分析问题的基础设施。根据可用的小型转储信息,您将获得所有线程的调用堆栈、传递给函数的参数、本地内容、加载和卸载的模块等。