我正在尝试遍历6张“国际象棋”棋子的列表。他们每回合移动一个随机量,如果降落在另一个回合上,就会“杀死”它。
问题是,当向量中的最后一个片段杀死另一个片段时,我将得到向量“超出范围”错误。我猜这是因为我正在遍历向量,同时还从其中移除了一些项,但是擦除一块时我没有增加计数,所以我不确定。任何帮助将不胜感激。
这是我的载体:
vector<Piece*> pieces;
pieces.push_back(&b);
pieces.push_back(&r);
pieces.push_back(&q);
pieces.push_back(&b2);
pieces.push_back(&r2);
pieces.push_back(&q2);
这是我使用的循环:
while (pieces.size() > 1) {
cout << "-------------- Round " << round << " --------------" << endl;
round++;
cout << pieces.size() << " pieces left" << endl;
i = 0;
while (i < pieces.size()) {
pieces.at(i)->move(board.getMaxLength());
j = 0;
while (j < pieces.size()) {
if (pieces.at(i) != pieces.at(j) && col.detectCollision(pieces.at(i), pieces.at(j))) {
cout << pieces.at(i)->getName() << " has slain " << pieces.at(j)->getName() << endl << endl;
pieces.at(i)->setKills(pieces.at(i)->getKills() + 1);
pieces.erase(pieces.begin() + j);
}
else {
j++;
}
}
i++;
}
}
解决方案
pieces.erase(pieces.begin() + j);
break;
答案 0 :(得分:3)
您的逻辑需要一些改进。
您编码的方式,似乎象棋的“基于回合”的性质已被一种“优先级列表”所取代-更接近矢量起点的棋子可以首先移动,因此,优先粉碎其他碎片。
我不知道您是否希望这种逻辑是对还是错。无论如何,麻烦似乎是由于无条件执行该行
i++;
如果由于未执行'j ++'的相同原因而删除一个片段,则不应执行该片段:您将跳过一个片段。
答案 1 :(得分:2)
我很强烈地认为这行代码:
i++;
是您的罪魁祸首,它缺少所需的中断条件或循环中缺少的其他条件检查。因为这取决于嵌套的while循环条件,因为它们基于向量的当前大小,因此不会相应地更新。
while (pieces.size() > 1) { // ... while (i < pieces.size()) { // ... while (j < pieces.size()) { // ... } } }
这是由于您在最嵌套的内部循环中调用此事实而引起的:
pieces.erase(pieces.begin() + j);
您位于嵌套的while循环内,如果满足特定条件,则将在向量中此索引位置处擦除对象,而您仍位于永不中断或检查的内部while循环内如果索引仍然有效。
最初,您使用带有6个条目的向量进入while循环,然后在嵌套循环内对其调用“擦除”,现在您的矢量具有5个条目。
这可能会对循环造成破坏,因为索引计数器i
和j
是根据向量的原始长度设置的,大小为6
,但是现在向量具有在您仍处于最内层嵌套循环中时,将其减小为5
的大小,您从不会中断该循环,也不会检查索引是否有效。现在,在下一次迭代中,这些值将变为无效,因为您永远不会中断循环来根据向量的新大小重置索引,也不必检查它们是否有效。
尝试运行这个简单的程序,该程序将演示嵌套循环中无效的索引的含义。
int main() {
std::vector<std::string> words{ "please", "erase", "me" };
std::cout << "Original Size: " << words.size() << '\n';
for (auto& s : words)
std::cout << s << " ";
std::cout << '\n';
words.erase(words.begin() + 2);
std::cout << "New Size: " << words.size() << '\n';
for (auto& s : words)
std::cout << s << " ";
std::cout << '\n';
return 0;
}
-输出-
Original Size: 3
please erase me
New Size: 2
please erase
答案 2 :(得分:1)
您应该在本地保存pieces.at(i)
,并在使用pieces.at(i)
的任何地方使用此本地变量。
要避免元素超出范围和逻辑问题,可以使用std::list
。
顺便说一句,仅当它们是非所有者指针时,才应使用std::vector<Piece*>
;否则,应使用智能指针,可能是unique_ptr
。