断言失败:列出迭代器不可递增(不在循环中)

Assertion failure: list iterator not incrementable (not in a loop)

本文关键字:循环 失败 迭代器 断言      更新时间:2023-10-16

首先,早上/白天/晚上好,感谢花时间阅读本文的人。

设置:

在我的代码中,我有两个不同的类:ColObj 和 QuadNode(即"碰撞对象"和四叉树中的一个节点,用于检查对象的接近程度。我知道可能有这方面的库,但我需要编写自己的系统,所以它们在这里没有用)。事情是这样的:当创建一个ColObj对象时,它被添加到一个适当的QuadNode中(该节点有一个std::指向ColObj的指针列表),以便节点可以在与某些东西发生冲突时通知它;ColObj 对象还接收一个指向持有它的节点的指针和一个指向包含其地址的列表迭代器的列表迭代器,因此当它超出节点的边界或被销毁时,它可以"离开"它,并清理节点,即从节点中删除并引用自身。我这样做是因为在很多情况下,这将是一个频繁的操作,我希望它处于恒定的时间。

守则:

这是用于将ColObj"附加"到QuadNode的方法。我怀疑问题不在这里。

void QuadNode::obj_add(ColObj *obj) {
std::cout<<"QuadNode at depth ("<<depth<<") received new ColObj.n";
objects.push_back(obj);
obj->holder  = this;
obj->my_iter = std::prev( objects.end() );
if ((int)objects.size() > MAX_OBJECTS && depth < MAX_DEPTH) split();
}

这是 ColObj 用来清理节点的 QuadNode 方法。这是由于某种原因出现问题的地方。

void QuadNode::obj_list_erase(std::list<ColObj*>::iterator iter) {
std::list<ColObj*>::iterator iter2 = objects.begin();
objects.erase(iter);
}

此方法中的第一行只是为调试提供其他信息,之后将被删除。

错误:

最奇怪的部分是,在大多数情况下,代码工作正常。然后在某一时刻,它随机抛出断言失败,说"列表迭代器不可增量"。这是第一件奇怪的事情,我并没有试图在我的代码中的任何地方增加它(尽管我知道 std::list::erase 返回以下迭代器,但我从未尝试在无效或"过去最后一个"迭代器上执行此操作)。

无论如何,Visual Studio提供了启动调试器并在代码中放置断点,所以我自然同意。所以这是最奇怪的部分:

局部变量和自动变量,调试器屏幕截图

(我无法嵌入图像,因为我是新来的,所以它就是这样)。

所以,除非我在这里严重错误,否则它告诉我传递的迭代器等于列表的开始迭代器,它的元素仍然存在于列表中并且对应于列表的第一个(或者更确切地说是零个)元素。然而,erase() 方法失败了。 值得一提的是,我注意到每次程序中断时,传递的迭代器都会指向列表的第 0 个元素,尽管我可以确认即使列表中只有一个元素,该方法通常也有效。

附加信息和结论:

我没有在代码中的其他任何地方手动递增迭代器(无论如何,这非常小且简单)。

我使用的IDE是Visual Studio Community 2015,但我不知道编译器版本。(Microsoft及其命名方案...

我尝试在 SO 上找到另一个关于此的线程,但我检查的每个线程都是关于在列表迭代中错误放置 i++ 的,所以很抱歉,如果这是一个重复的线程。

我对这个问题完全感到困惑,因为通常在出色的调试器,std::cout和浏览之间,我以某种方式解决了这个问题,但是这次没有任何有用的东西出现,所以任何建议或建议将非常受欢迎。

编辑:

我尝试过"只是'原因"编辑 QuadNode::obj_list_erase 方法,以便它将传递的迭代器与其列表的第一个迭代器 (objects.begin()) 进行比较,如果它们是平等的,则使用 objects.pop() 删除它,否则正常擦除它。它不起作用,说迭代器不兼容,无论这意味着什么......

在发现我什至无法将传递的迭代器与列表中应该保存它的任何其他迭代器进行比较后(我得到了断言失败:迭代器不兼容),我搜索了 SO 以获取有关它的含义的更多信息,并且......安德鲁·卡什布尔是对的。我确实设法通过从列表中删除指向的元素并立即将其放回原处来使迭代器无效,但没有更新迭代器。

故事的寓意:迭代器似乎指向一个"正确"的内存位置,它甚至可能指向与某些有效迭代器相同的地址,但这并不能使其有效或兼容。