简体   繁体   English

调试断言:向量迭代器不兼容(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)));
                }
            }
        }
    }

Hey Guys, i have some problems with the upper code. 大家好,我在上层代码方面遇到了一些问题。 The code snippet is supposed to find all the spawns in a 2d game field. 该代码段应能找到2d游戏场中的所有生成物。 WHen it comes to the head of the third for-iteration it spits out a Debug assertion error with the following message "Vector iterators incompatible. Now this are the values one step before the crash . I got them form the visual studio debugger: 当它出现在第三个迭代的开头时,它会发出Debug断言错误,并显示以下消息:“ Vector迭代器不兼容。现在这是崩溃之前的一步。我从Visual Studio调试器中获取了它们:

getElements() returned {size = 0};i = 0;j = 0; getElements()返回了{size = 0}; i = 0; j = 0; begin() returned struct at null. begin()返回null的struct。 it is struct at null 它是NULL结构

I see that the vector is empty, but shouldn't that be handled by the it != end() part? 我看到向量为空,但是不应该由it!= end()部分处理吗?

You have not posted enough code to be really sure, but the following guess should be correct: 您尚未发布足够的代码来确定,但是以下猜测应该是正确的:

getElements() most likely returns by value, not by reference. getElements()最有可能通过值而不是通过引用返回。

For example: 例如:

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

This returns a copy ! 这将返回副本 Which means that every time you call getElements , you get a different vector. 这意味着每次调用getElements ,都会得到一个不同的向量。

For the compiler, this does not make any difference. 对于编译器,这没有任何区别。 Type safety does not help you, because a std::vector<std::shared_ptr<GameGridElement>>::iterator is a std::vector<std::shared_ptr<GameGridElement>>::iterator , even if you have two iterators which belong to different container instances . 类型安全性对您没有帮助,因为std::vector<std::shared_ptr<GameGridElement>>::iteratorstd::vector<std::shared_ptr<GameGridElement>>::iterator即使您有两个迭代器属于不同的容器实例 They have the same type, so the code compiles. 它们具有相同的类型,因此代码可以编译。

At run time, however, additional checks can be made to ensure that two iterators that are being compared really belong to the same container object. 但是,在运行时,可以进行其他检查以确保正在比较的两个迭代器确实属于同一容器对象。 This turns seemingly random "strange" behaviour or spurious crashes into a definite guaranteed crash to immediately tell you that something must be fixed. 这将看似随机的“奇怪”行为或虚假崩溃转变为确定的保证崩溃,以立即告诉您必须修复某些问题。

Consider again this line: 再次考虑以下这一行:

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 is initialised to getElements().begin() and is then compared by != to getElements().end() . it被初始化为getElements().begin() ,然后由!=getElements().end() But as explained above, each getElements() returns a different vector, so you get incompatible iterators. 但是如上所述,每个getElements()返回一个不同的向量,因此您获得了不兼容的迭代器。

Here is an easy way to solve the problem: 这是解决问题的简单方法:

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)

This makes sure that begin() and end() return iterators to the same container instance. 这样可以确保begin()end()将迭代器返回到相同的容器实例。


For reference, here is a simple piece of code to reproduce the behaviour: 作为参考,下面是一段简单的代码来重现该行为:

#include <vector>

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

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

Note that the C++ standard does not mandate iterator-compatibility checks at run time. 请注意,C ++标准没有在运行时强制进行迭代器兼容性检查。 Your compiler has to offer them and you must use the correct compiler options to enable them, or disable them if you don't need them or cannot afford them. 您的编译器必须提供它们,并且您必须使用正确的编译器选项来启用它们,或者在不需要或负担不起它们时禁用它们。


By the way, if you can use C++11, then you can use a range-based for loop to not only fix the bug but also make the code a lot more concise. 顺便说一句,如果您可以使用C ++ 11,则可以使用基于范围的for循环不仅可以修复错误,还可以使代码更加简洁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM