发布模式下的异常,而不是调试模式下的异常
Posted
技术标签:
【中文标题】发布模式下的异常,而不是调试模式下的异常【英文标题】:exception in release mode and not in debug mode 【发布时间】:2013-05-20 12:17:23 【问题描述】:当我在调试模式下运行这段代码时没有出现异常,但在发布模式下我得到了这个异常:
RealTimeSLT.exe 中 0x768b4b32 处未处理的异常:Microsoft C++ 异常: cv::Exception at memory location 0x003de734..
为什么这个问题只在发布时出现?我该如何解决??
FileStorage fs2(fileName, FileStorage::READ);
fs2.open(fileName, FileStorage::READ);
fs2["Mat"] >> Mat;
fs2["dMat"]>> dMat;
fs2.release();
【问题讨论】:
OpenCV cv::FileStorage 类在无法打开文件时抛出异常。捕捉该异常并告诉用户选择另一个文件是明智的。或者在代码中使用文件的正确路径名。 你不需要调用open()
作为之前已经使用指定参数调用它的行。基本上,您现在正在打开、关闭和重新打开文件。
如果路径不是明确的但相对于工作目录,当你运行可执行文件时它不会找到它是一个不同的目录。有时 Debug 和 Release 使用不同的工作目录。检查项目配置。
在 VS 调试版本中,未初始化的裸指针通常会代表您初始化为 null。如果您的代码中有任何裸指针忘记初始化为 null,它们将指向发布版本中的垃圾位置,取消引用将是未定义的行为。
【参考方案1】:
假设你在 VS 中运行,选择 Debug->Exceptions 并点击 'Break When Exception is Thrown'
在调试器下运行应用程序,看看为什么会抛出异常以及它抱怨什么 - 这很可能是应用程序运行环境不同的原因。
如果您需要检查变量,那么发布构建会使这变得困难,因为优化器可能会使调试器感到困惑。您可以通过关闭发布版本中的优化来解决这个问题。但是,如果是时间问题,这可能会隐藏问题。
另一个选项是捕获抛出的异常,然后记录其内部消息——这通常是一个名为“what()”或类似的函数。这很可能会指出实际问题。无论如何,您可能都希望捕获此异常。
如果它的未定义行为导致了 Release 和 Debug 之间的差异,那么上面的可能不会有那么多用处。
【讨论】:
【参考方案2】:代码看起来很奇怪。
在不了解您的 FileStorage 对象的情况下,我可以看到您在第一行的堆栈上创建了一个。
假设 release() 是某种引用计数方法,fs2.release() 将尝试删除它,因为引用计数为零。
删除已分配在堆栈上的对象不好。你会崩溃的。
无论是 (1),还是试试这个(即在堆上分配)
FileStorage fs2 = new FileStorage(fileName, FileStorage::READ);
(假设对象具有内置的引用计数语义;请查看文档)。
或 2: 删除最后一行,因为 fs2 将在堆栈展开时超出范围。
【讨论】:
虽然这在一般情况下可能是个好建议,但在这个特定的建议中你错了:OpenCV 的FileStorage::release()
不会删除对象,而是关闭文件并释放内部缓冲区。读完文件后调用它完全没问题,见docs.opencv.org/modules/core/doc/xml_yaml_persistence.html
奇怪的是调试和发布行为差异如此之大。这就是为什么我在考虑调试和释放堆时发现了错误的树。【参考方案3】:
当你处于发布模式时,你需要再次将“*.lib”文件添加到 vs 项目的链接器。 我认为这是2.4.1之后opencv的一个错误。
【讨论】:
【参考方案4】:就我而言,这是因为 OpenCV 库是用 VS2010 构建的,而我使用的是 VS2015。
为了解决问题,我更改了我的项目属性 > 常规 > 平台工具集,以匹配用于构建我链接的 opencv 库的工具集。
【讨论】:
以上是关于发布模式下的异常,而不是调试模式下的异常的主要内容,如果未能解决你的问题,请参考以下文章
如何在 C++Builder 发布模式下找到异常,但不是调试
带有 multidex 的 Xamarin Android - 调试模式下的错误