迭代器偶尔会出现分段错误

Posted

技术标签:

【中文标题】迭代器偶尔会出现分段错误【英文标题】:Occasionally Segmentation Fault with iterators 【发布时间】:2014-01-12 00:54:23 【问题描述】:

我目前正在开发一个关于能够从绘制的图像中创建可玩游戏关卡的应用程序的项目(可以在此处找到:Github)。为此,我使用 openCV 进行图像处理。 我的问题是一个函数,它应该将检测到的线(即关卡中的“墙壁”)绘制到图像上。

void LineFinder::drawDetectedLines( cv::Scalar color)

    for (auto it = Play::getInstance()->getFinder()->getLines().begin(); it != Play::getInstance()->getFinder()->getLines().end(); ++it)
    
        // The lines are stored in an std::vector<cv::Vec4i>, 
        // so basically in a vector which contains vectors with 4 elements each
        cv::Point pt1((*it)[0], (*it)[1]);
        cv::Point pt2((*it)[2], (*it)[3]);

        // draws a line from pt1 to pt2
        cv::line(Play::getInstance()->getFinder()->getImage(), pt1, pt2, color);

        ++it;
    

当这个函数执行时,大多数时候我会遇到分段错误,但有时它会起作用并且结果与我预期的一样。我知道向量包含元素。 那么您能想到导致这种行为的任何可能原因吗?

编辑:有趣的是,当使用这个函数的函数已经成功执行一次时,我可以一次又一次地重新执行它并且没有错误发生。

EDIT2:我仍然不知道为什么迭代器会出现分段错误,但没有它们它会以某种方式工作:

void LineFinder::drawDetectedLines( cv::Scalar color)

    for (int i = 0; i < Play::getInstance()->getFinder()->getLines().size(); ++i)
    
        cv::Point pt1(Play::getInstance()->getFinder()->getLines()[i][0], Play::getInstance()->getFinder()->getLines()[i][1]);
        cv::Point pt2(Play::getInstance()->getFinder()->getLines()[i][2], Play::getInstance()->getFinder()->getLines()[i][3]);

        cv::line(Play::getInstance()->getFinder()->getImage(), pt1, pt2, color);
    

【问题讨论】:

您是否使用调试器来查找段错误的行/堆栈跟踪?是每次都一样还是每次运行都会改变? 您是指导致错误的行吗?这是与 pt1 的行。 【参考方案1】:

您将迭代器递增两次。来到这里:

for (auto it = Play::getInstance()->getFinder()->getLines().begin(); it != Play::getInstance()->getFinder()->getLines().end(); ++it)

在这里一次:

++it;

您可能会增加超过 end() 迭代器,从而导致未定义的行为。

编辑:

您的帖子中没有足够的信息来识别其他问题,尤其是我不知道所有变量和函数是什么。我也不想爬过整个 git。

所以这里有一些可能的问题:

    Play::getInstance()-&gt;getFinder()-&gt;getLines() 是否保证总是返回对同一个容器的引用?

    返回的容器是否保证在您迭代时不会被修改?

    存储在容器中的对象是否保证是数组/向量/...至少有4个元素?

编辑2:

好吧,我看了一眼您的存储库,linefinder.cpp 中有错误:

std::vector<cv::Vec4i> LineFinder::getLines()

    return lines;

getLines() 确实返回对同一容器的引用,它在每次调用时返回一个副本。因此,您在 for 循环中不断将一个容器的迭代器与另一个容器的迭代器进行比较。要么将定义更改为引用返回:

std::vector<cv::Vec4i>& LineFinder::getLines()

    return lines;

或在构造迭代器之前保存返回值:

auto lines = Play::getInstance()->getFinder()->getLines();
for (auto it = lines.begin(); it != lines.end(); ++it)

【讨论】:

好的,但是在删除 '++it;' 之后仍然有这种奇怪的行为。顺便说一句,存在这条线是因为曾经有一个 while 循环导致了同样的问题。 @BlackMamba 我扩展了我的答案(再次)

以上是关于迭代器偶尔会出现分段错误的主要内容,如果未能解决你的问题,请参考以下文章

向量和迭代器的分段错误? [关闭]

带有向量迭代器的程序中的分段错误

为啥我在这个迭代器中遇到分段错误?

用于向量向量的 c++ 迭代器

迭代器未按预期运行

无法使用迭代器迭代具有数组类型的 GVariant