矢量越界

时间:2018-12-07 17:28:31

标签: c++ vector

我正在尝试遍历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;

3 个答案:

答案 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个条目。

这可能会对循环造成破坏,因为索引计数器ij是根据向量的原始长度设置的,大小为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