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

编程入门 行业动态 更新时间:2024-10-21 23:13:32
本文介绍了调试断言:向量迭代器不兼容 (C++)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

for (int i = 0; i dimensions()->first; i++){for (int j = 0; j 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()pare("Spawn") == 0){tmpSpawns.push_back(std::static_pointer_cast((*it)));}}}}

嘿,伙计们,我对上层代码有一些问题.代码片段应该在 2d 游戏字段中找到所有生成物.当涉及到第三次迭代的头部时,它会吐出一个调试断言错误,并显示以下消息向量迭代器不兼容.现在这是崩溃前一步的值.我从 Visual Studio 调试器中得到它们:

getElements() 返回 {size = 0};i = 0;j = 0;begin() 返回空结构.它是空的结构

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

解决方案

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

getElements() 很可能是按值返回,而不是按引用返回.

例如:

std::vector字段::getElements(){//...返回结果;}

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

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

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

再次考虑这一行:

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

it 被初始化为 getElements().begin(),然后通过 != 与 getElements() 进行比较.结束().但是如上所述,每个 getElements() 返回不同的向量,因此您会得到不兼容的迭代器.

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

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

这确保 begin() 和 end() 将迭代器返回到同一个容器实例.

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

#include int main(){std::vectorv1;std::vectorv2;bool b = v1.begin() == v2.begin();}

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

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

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()pare("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. 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:

getElements() returned {size = 0};i = 0;j = 0; begin() returned struct at null. it is struct at null

I see that the vector is empty, but shouldn't that be handled by the it != end() part?

解决方案

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.

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.

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. 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(). But as explained above, each getElements() returns a different vector, so you get incompatible iterators.

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.

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. 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++)

本文发布于:2023-07-30 00:32:02,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1244981.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:向量   断言   不兼容   迭代

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!