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游戏领域中的所有产生。当它出现在第三次迭代的头部时,它会发出一个Debug断言错误,并显示以下消息&#34; Vector迭代器不兼容。现在这是崩溃前一步的值。我将它们从visual studio调试器中获取:
getElements()返回{size = 0}; i = 0; j = 0; begin()在null返回struct。它是struct at null
我看到向量是空的,但不应该由它来处理它!= end()部分?
答案 0 :(得分:3)
您尚未发布足够的代码以确定,但以下猜测应该是正确的:
getElements()
最有可能按值返回,而不是按引用返回。
例如:
std::vector<std::shared_ptr<GameGridElement>> Field::getElements()
{
// ...
return result;
}
这会返回副本!这意味着每次拨打getElements
时,都会获得不同的向量。
对于编译器,这没有任何区别。类型安全对您没有帮助,因为std::vector<std::shared_ptr<GameGridElement>>::iterator
是std::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
循环来解决错误,同时使代码更加简洁。