调试断言:Vector迭代器不兼容(c++)

Debug Assertion : Vector iterators incompatible (C++)

本文关键字:c++ 不兼容 迭代器 断言 Vector 调试      更新时间:2023-10-16
for (int i = 0; i < m_pGameField->dimensions()->first; i++)
    {
        for (int j = 0; j < m_pGameField->dimensions()->second; j++)
        {
            for (std::vector<std::shared_ptr<GameGridElement>>::iterator it = m_pGameField->getField(i, j)->getElements().begin();it != m_pGameField->getField(i, j)->getElements().end(); ++it)
            {
                if ((*it)->getName().compare("Spawn") == 0)
                {
                    tmpSpawns.push_back(std::static_pointer_cast<SpawnElement>((*it)));
                }
            }
        }
    }

嘿伙计们,上面的代码有些问题。代码片段应该找到2d游戏领域中的所有刷出。当它到达第三次for迭代的头部时,它会抛出一个Debug断言错误,并显示以下消息"Vector迭代器不兼容"。这是崩溃前一步的值。我从visual studio调试器中得到它们:

getElements()返回{size = 0};i = 0;Begin()返回null的结构体。它是null

我看到向量是空的,但这不应该由it != end()部分处理吗?

您没有发布足够的代码来真正确定,但以下猜测应该是正确的:

getElements()最有可能按值返回,而不是按引用返回。

例如:

std::vector<std::shared_ptr<GameGridElement>> Field::getElements()
{
    // ...
    return result;
}

返回一个副本!这意味着每次调用getElements,你会得到一个不同的向量。

对于编译器来说,这没有任何区别。类型安全对您没有帮助,因为std::vector<std::shared_ptr<GameGridElement>>::iteratorstd::vector<std::shared_ptr<GameGridElement>>::iterator,即使您有两个属于不同容器实例的迭代器。它们具有相同的类型,因此代码可以编译。

然而,在运行时,可以进行额外的检查,以确保正在比较的两个迭代器确实属于同一个容器对象。这会将看似随机的"奇怪"行为或虚假的崩溃转变为明确的保证崩溃,以立即告诉您必须修复某些内容。

再考虑这一行:

for (
    std::vector<std::shared_ptr<GameGridElement>>::iterator
        it = m_pGameField->getField(i, j)->getElements().begin();
        it != m_pGameField->getField(i, j)->getElements().end();
    ++it
)

it初始化为getElements().begin(),然后由!=getElements().end()进行比较。但是如上所述,每个getElements()返回一个不同的向量,因此得到不兼容的迭代器。

这里有一个简单的方法来解决这个问题:

std::vector<std::shared_ptr<GameGridElement>> elements =
    m_pGameField->getField(i, j)->getElements();
for (std::vector<std::shared_ptr<GameGridElement>>::iterator it = elements.begin();
    it != elements.end(); ++it)

这确保了begin()end()返回的迭代器指向同一个容器实例。


作为参考,这里有一段简单的代码来重现这种行为:

#include <vector>
int main()
{
    std::vector<int> v1;
    std::vector<int> v2;
    bool b = v1.begin() == v2.begin();
}

注意c++标准并没有强制要求在运行时检查迭代器的兼容性。你的编译器必须提供它们,你必须使用正确的编译器选项来启用它们,或者在你不需要它们或负担不起它们时禁用它们。


顺便说一下,如果您可以使用c++ 11,那么您可以使用基于范围的for循环,不仅可以修复错误,还可以使代码更加简洁。