调试断言:向量迭代器不兼容 (C++)

Debug Assertion : Vector iterators incompatible (C++)

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 迭代的开头时,它会吐出一个调试断言错误,并显示以下消息“向量迭代器不兼容。现在这是崩溃前一步的值。我从 visual studio 调试器中获取了它们:

getElements() 返回 {size = 0};i = 0;j = 0; begin() 返回的结构为 null。它是 null

的结构

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

您发布的代码还不够多,无法确定,但以下猜测应该是正确的:

getElements() 最有可能 return 按值计算,而不是按引用计算。

例如:

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

这个return是一个副本!这意味着每次调用 getElements 时,您都会得到一个 不同的 向量。

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

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

再次考虑这一行:

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() return 都是一个不同的向量,所以你会得到不兼容的迭代器。

这是解决问题的简单方法:

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() return 迭代器指向同一个容器实例。


作为参考,这里有一段简单的代码可以重现该行为:

#include <vector>

int main()
{
    std::vector<int> v1;
    std::vector<int> v2;

    bool b = v1.begin() == v2.begin();
}

请注意,C++ 标准不要求在 运行 时进行迭代器兼容性检查。您的编译器必须提供它们并且您必须使用正确的编译器选项来启用它们,或者如果您不需要它们或负担不起它们则禁用它们。


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