c++ STL矢量擦除

C++ STL vector erase

本文关键字:擦除 STL c++      更新时间:2023-10-16

问题是,当我运行函数时,它在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);
        }
    }
}

当你擦除一个元素时,vector会变小;但你还是用原来的尺寸,并且从末端脱落。此外,您不希望在擦除后增加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"习语的其他答案,这是避免这种容易出错的逻辑的一种很好的,也许更有效的方法。

看起来你应该使用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解决方案需要二次时间。

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;
}