2

问题是,当我运行该功能时,它会在该erase部分崩溃,我无法弄清楚原因。

void Grupa::del() {
    int size = studenti.size();
    for (int i=0; i<size; i++) {
        if (studenti[i].materia1<5 && studenti[i].materia2<5 && studenti[i].materia3<5) {
        studenti.erase(studenti.begin()+i);
        }
    }
}
4

3 回答 3

12

当你擦除一个元素时,向量会变小;但是您仍在使用原始尺寸,并且最终掉了下来。此外,您不想i在擦除后增加,否则您将在擦除后跳过元素。所以你想要这样的东西:

for (size_t i = 0; 
     i != studenti.size(); // don't hoist out of the loop
     /* don't increment here */) 
{
    if (...) {
        studenti.erase(studenti.begin()+i);
    } else {
        ++i;
    }
}

或者查看“erase-remove”习语的其他答案,这是一种避免这种容易出错的逻辑的好方法,而且可能更有效。

于 2013-05-28T18:55:35.290 回答
6

看起来您应该使用 STL 算法,std::remove_if而不是这个,这样可以方便地避免其他回答者已经指出的问题。考虑一下:

studenti.erase(std::remove_if(studenti.cbegin(), studenti.cend(), [](Student const& currentStudent) {
    return currentStudent.materia1<5 && currentStudent.materia2<5 && currentStudent.materia3<5;
}), studenti.cend());

请注意,这与您的解决方案相比具有优势,因为它需要相对于向量中元素数量的线性时间,而 for/erase 解决方案需要二次时间。

于 2013-05-28T18:59:02.030 回答
0

i超出向量的大小。由于erase调用,向量的大小变得更小,但你会一直到保存的大小,如果有已删除的项目,它会大于实际大小。

这就是为什么erase返回一个迭代器,它是一个有效的迭代器,指向被擦除元素旁边的元素:

for (auto it = studenti.begin(); it != studenti.end();) {
    if (it->materia1<5 && it->materia2<5 && it->materia3<5)
        it = studenti.erase(it);
    else
        ++it;
}
于 2013-05-28T18:55:38.370 回答