【问题标题】:C++ Compilation introduce errorsC++ 编译引入错误
【发布时间】:2014-03-26 17:57:26
【问题描述】:

我在 Visual Studio 2010 中有一个使用 Qt (5.1.1) 和 OpenCV (2.4.8) 的多线程 C++ windows 项目。当我在 Debug 模式下构建它时,一切运行正常,但是当我在 Release 模式下构建它时,程序崩溃了。两种配置几乎相同(只是在 Release 中我有 Multi-threaded DLL /MD 和在 Debug Multi-threaded Debug DLL /MDd 中),我禁用了 Release 的优化,甚至启用了调试以捕获错误。最奇怪的是,同一段代码崩溃了,在另一个控制台项目中运行得很好。

错误是OpenCV代码内部的,与我的代码无关,我的代码只是:

void MyProject::findEllipses(QImage &frame, vector<RotatedRect> &ellipses)
{       
    Mat image = Mat(frame.height(), frame.width(), CV_8UC4, frame.scanLine(0));                 

    cvtColor(image, image, CV_RGB2GRAY);
    GaussianBlur(image, image, Size(3, 3), 0, 0, 4);            
    threshold(image, image, treshVal, 255, THRESH_BINARY);

    vector<vector<Point> > contours;               
    Mat contoursImage = image.clone();    
    findContours(contoursImage, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE, Point(0, 0)); 
// ....Mode Code

正如我在 Debug 中所说,代码运行没有问题,findContours 调用 _contours.create(total, 1, 0, -1, true);(在 OpenCV 的 contours.cpp 的第 1720 行)并继续使用该方法....但是在Release,当我进入_contours.create(total, 1, 0, -1, true) 时,程序没有执行该方法,而是跳转到void _OutputArray::clear() const(matrix.cpp 的第1674 行)并被困在那里,因为它调用int k = kind();在它的第一行,而不是调用cv::kind(),调用:

 int _InputArray::type(int i) const
 {
    int k = kind();

再次调用kind() 再次调用type()(而不是应有的kind()),进行无限递归循环,带来堆栈溢出

我尝试创建一个新的 Visual Studio 2010 项目以查看这是否是项目创建问题,但问题仍然存在。

我的猜测是函数地址在发布模式下是错误的,所以当它尝试调用 create() 时,它会调用另一个地址,从而在堆栈中造成混乱,但这只是我的猜测。起初我会责怪 OpenCV 发布 dll,但是,正如我所说,在另一个只运行该特定代码的控制台项目中,代码在 bot 构建模式下运行良好。我看不到我的其他线程和代码如何触发此行为,因为错误归结为 OpenCV 中的错误函数调用。

这超出了我的知识范围,我不知道如何解决这个问题,我感谢我能在这个问题上获得的所有帮助,因为我已经用尽了所有的想法来解决它......

编辑:

我做了一个小项目,这样任何人都可以看到正在发生的事情。

文件位于: https://app.box.com/s/3owljl44emv57erinrf8

为了运行它,您必须拥有 OpenCV 2.4.8 和 Qt 5.1.1 并配置 Visual Studio 2010 项目以从正确的位置获取包含文件。在资源文件夹中有一个要加载的图像,在 SaraVisualControl.cpp 第 20 行中,您必须放置图像的正确路径,抱歉我没有自动设置,但我急于打包一个小项目。有关如何运行它的任何其他问题,请告诉我。

编辑 2

我发现了这个旧线程:http://code.opencv.org/issues/2218 用户似乎遇到了与我相同的问题,并且仅在关闭 OPENCV_CAN_BREAK_BINARY_COMPATIBILITY 的情况下运行 CMake 似乎可以解决它。但是这个选项不再出现在新版本的 OpenCV 中,如http://code.opencv.org/issues/2358 所述。有谁知道这意味着什么以及它可能是如何相关的?

【问题讨论】:

  • 使用调试器,在你的代码中设置一个断点,在那里你调用崩溃的函数,检查输入 - 它是否都有效,所有输入指针是否都实际指向对象等等。你是可能在某处调用未定义的行为。
  • 嗯,这正是我如何捕捉到该错误...我用断点检查了它,并进入了函数...在调试模式下它会在它应该执行的位置...在发布它不会。 ..就这么简单:) 是的,所有输入都是有效的
  • 最简单的修复方法可能是在您的项目中包含 OpenCV 源代码(否则确保编译器开关匹配)
  • 确保您的调试器中显示的堆栈跟踪是正常的,并且实际显示正在发生的事情,因为在发布模式下通常无法信任调试器。
  • @DieterLücking 我自己重新编译了 OpenCV 以获得 dll 的 .pdb,这样我就可以进入 OpenCV 函数

标签: c++ visual-studio-2010 qt opencv


【解决方案1】:

我过去在混合 VC 运行时版本时遇到过类似的症状。如果您在 VC2010 中工作并且 OpenCV 2.4.8 是在 2012 年甚至 2013 年构建的,那么您的 ABI 不匹配。例如,std::vector 在内存中的布局不同,可能某个 vtable 中某些方法的顺序发生了变化,等等。

一个简单的测试方法是在调试时检查“模块”窗口并查找更高版本的运行时 dll。你的是 msvcr100d.dll,如果你看到 msvcr110d 或 120d - 这可能是来源。 (假设您和 OpenCV 都动态链接到 CRT - 我无法确定)。

【讨论】:

  • 我不是这种情况,因为我自己重新编译了 dll 以检查这个错误,我在 VS2010 中做到了。我检查了模块窗口,我只有 msvcr100.dll、msvcp100.dll 和 msvcrt.dll
  • 另外,在我使用自己的库之前,我是从 OpenCV 的 vs2010 文件夹中获取它们的
  • 好的。另一个候选者是在编译您的项目/openCV 时出现一些标题差异。但在测试之前 - 我建议您确保对 _contours.create 的调用没有发生在另一行。在发布中,代码行和指令之间的匹配是启发式的——您可以尝试在 _contours.create 的入口处设置断点,并验证它在发布中没有命中。
  • 我做到了,但它没有被触发……这对我来说真的很沮丧,因为这是我的第一个 C++ 项目,所以我有点害怕再次使用 C++。我觉得我无法控制程序
  • 好的 - 请只编译调用和实现 _contours.create() 的两个文件,将“显示包含”设置为“是”,并说明您是否在包含的标头的路径中发现任何差异。此外 - 如果您可以将上传的示例缩减为更独立的内容,那么它会更容易为您提供帮助。你能在没有 Qt 依赖的情况下重现问题吗?你能在包中只包含相关的 OpenCV 头文件吗?
【解决方案2】:

debug和release在内存分配上是不同的。通常在调试模式下分配更大。 可能是您滥用了一些 openCV 调用,但您不知道。 我会采取下一步行动:

  1. 验证框架是否正常。可能是太大了,或者宽度或高度没有启动;

  2. 验证下一行之后图像变量是否正常

    Mat image = Mat(frame.height(), frame.width(), CV_8UC4,rame.scanLine(0));

  3. 在第一个和第二个参数相同的情况下调用 cvtColor 是否可以(可能是你在这里滥用了 CV)

  4. 在第一个和第二个参数相同的情况下调用 GaussianBlur 可以吗?尝试放置不同的第二个参数

  5. 阈值函数调用也是如此

  6. 检查 image.clone 调用后,countoursImage 是一个有效的矩阵。

【讨论】:

  • 我看不出这个函数会有什么问题,因为同样的代码在另一个项目(控制台项目)中运行良好......是的,所有使用相同输入和输出的函数都是预计会这样做。
【解决方案3】:

我猜:除了检查库本身是否正确之外,还要检查您是否以相同的顺序指定了所有库(在所有构建中)。否则,链接器可能会在最后的链接器阶段将函数名称绑定到不同的实现。

【讨论】:

  • 我检查了链接器>输入,并且所有输入的顺序都相同...我还应该检查其他地方吗?
  • 您写道,您是这样检查的:您在 Debug-Build 中进入 _contours.create(total, 1, 0, -1, true);,在 Release-Build 中进入 _contours.create()。我不知道代码。但是,这显然是两个不同的功能。为什么你期望相同的行为?一个人通常会打电话给另一个人吗?
  • 如果不是,那么链接器实际上将错误的函数绑定到您的symbols。您是否尝试过静态链接?
  • 尝试更多verbose build,也许你在构建命令行上注意到了一些东西。如果其他一切都失败了,请在 Studio 项目配置中为 LIB 使用绝对路径名。这将确保您实际使用所有正确的 LIB(包括系统依赖项)。如果错误仍然发生,它必须与构建标志有关。
  • 对不起,我的错,它是同一个功能,我只是不想输入2次,所以我用()缩写,我会编辑它,以便清楚。
【解决方案4】:

我遇到了同样的问题。我使用的是 Qt 5.1.1 和 opencv248,我的应用程序在从 findcontours 返回后崩溃了。原来我在 pro 文件中使用了 vc10 库和相应的 dll,而使用的 Qt 编译器是 msvc2013。切换到 opencv 248 中的 vc12 文件夹为我解决了这个问题。

【讨论】:

    【解决方案5】:

    您是否检查过您的 opencv 库的发布版本。 Opencv 有一组不同的库用于发布和调试版本。如果您已经在发布模式中包含调试库。您的代码将毫无错误地编译,但在执行时会抛出异常。 要检查您的库,请转到

    Project-&gt;Properties-&gt;Configuration Properties-&gt;linker-&gt;Input-&gt;Additional Dependencies.

    确保您的任何 Opencv 库都没有以“d”结尾的发布模式。

    发布库:'opencv_core248.lib'

    调试库:'opencv_core248d.lib'

    注意调试模式末尾的 d

    我希望这会有所帮助。

    【讨论】:

    • 是的,我知道这一点并且我确信它们都是正确的,我对此进行了三次检查,并且我还编译了我自己的 OpenCV 库以进一步调试错误。您可以在 .rar 中看到正确文件夹中的所有调试和发布 dll
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多