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 に答える