it-swarm.com.de

vektor löschen Iterator

Ich habe diesen Code:

int main()
{
    vector<int> res;
    res.Push_back(1);
    vector<int>::iterator it = res.begin();
    for( ; it != res.end(); it++)
    {
        it = res.erase(it);
        //if(it == res.end())
        //  return 0;
    }
}

"Ein Iterator mit wahlfreiem Zugriff, der auf die neue Position des Elements zeigt, das auf das letzte durch den Funktionsaufruf gelöschte Element folgte, das das Vektorende ist, wenn die Operation das letzte Element in der Sequenz gelöscht hat."

Dieser Code stürzt ab, aber wenn ich das if (es == res.end ()) verwende, dann kehrt es zurück. Wie kommt es? Macht die for-Schleife das res.end (), so dass der nicht gleichwertige Operator ausfällt?

59
hidayat

res.erase(it) gibt immer den nächsten gültigen Iterator zurück. Wenn Sie das letzte Element löschen, zeigt es auf .end().

Am Ende der Schleife wird ++it immer aufgerufen, also erhöhen Sie .end(), was nicht zulässig ist. 

Wenn Sie einfach nach .end() suchen, bleibt ein Fehler, da Sie bei jeder Iteration immer ein Element überspringen (it wird durch die Rückkehr von .erase() und dann erneut durch die Schleife "inkrementiert").

Sie wollen wahrscheinlich etwas wie:

 while (it != res.end()) {
        it = res.erase(it);    
 }

jedes Element löschen

(Der Vollständigkeit halber gehe ich davon aus, dass dies ein vereinfachtes Beispiel ist. Wenn Sie einfach wollen, dass jedes Element gelöscht wird, ohne dafür eine Operation ausführen zu müssen (z. B. löschen), rufen Sie einfach res.clear() auf.)

Wenn Sie Elemente nur bedingt löschen, möchten Sie wahrscheinlich so etwas wie

for ( ; it != res.end(); ) {
  if (condition) {
    it = res.erase(it);
  } else {
    ++it;
  }
}
129
Pieter
for( ; it != res.end();)
{
    it = res.erase(it);
}

oder allgemeiner:

for( ; it != res.end();)
{
    if (smth)
        it = res.erase(it);
    else
        ++it;
}
27
crazylammer

Als Modifikation der Antwort von Crazylammer verwende ich häufig:

your_vector_type::iterator it;
for( it = res.start(); it != res.end();)
{
    your_vector_type::iterator curr = it++;
    if (something)
        res.erase(curr);
}

Dies hat den Vorteil, dass Sie sich keine Sorgen machen müssen, dass Sie vergessen, Ihren Iterator zu inkrementieren. Innerhalb der Schleife ist curr niemals gleich res.end (), und es ist das nächste Element, unabhängig davon, ob Sie es aus Ihrem Vektor löschen. 

1
Joseph Petroske

Weil die Methode delete in vector den nächsten Iterator des übergebenen Iterators zurückgibt.

Ich werde ein Beispiel geben, wie das Element im Vektor beim Durchlaufen entfernt wird.

void test_del_vector(){
    std::vector<int> vecInt{0, 1, 2, 3, 4, 5};

    //method 1
    for(auto it = vecInt.begin();it != vecInt.end();){
        if(*it % 2){// remove all the odds
            it = vecInt.erase(it); // note it will = next(it) after erase
        } else{
            ++it;
        }
    }

    // output all the remaining elements
    for(auto const& it:vecInt)std::cout<<it;
    std::cout<<std::endl;

    // recreate vecInt, and use method 2
    vecInt = {0, 1, 2, 3, 4, 5};
    //method 2
    for(auto it=std::begin(vecInt);it!=std::end(vecInt);){
        if (*it % 2){
            it = vecInt.erase(it);
        }else{
            ++it;
        }
    }

    // output all the remaining elements
    for(auto const& it:vecInt)std::cout<<it;
    std::cout<<std::endl;

    // recreate vecInt, and use method 3
    vecInt = {0, 1, 2, 3, 4, 5};
    //method 3
    vecInt.erase(std::remove_if(vecInt.begin(), vecInt.end(),
                 [](const int a){return a % 2;}),
                 vecInt.end());

    // output all the remaining elements
    for(auto const& it:vecInt)std::cout<<it;
    std::cout<<std::endl;

}

ausgabe aw unten:

024
024
024

Eine weitere Generierungsmethode:

template<class Container, class F>
void erase_where(Container& c, F&& f)
{
    c.erase(std::remove_if(c.begin(), c.end(),std::forward<F>(f)),
            c.end());
}

void test_del_vector(){
    std::vector<int> vecInt{0, 1, 2, 3, 4, 5};
    //method 4
    auto is_odd = [](int x){return x % 2;};
    erase_where(vecInt, is_odd);

    // output all the remaining elements
    for(auto const& it:vecInt)std::cout<<it;
    std::cout<<std::endl;    
}
0
Jayhello

Löschen Sie den Iterator nicht und erhöhen Sie ihn dann. Keine Notwendigkeit zu erhöhen, wenn Ihr Vektor eine ungerade Anzahl von Elementen hat (oder sogar, ich weiß es nicht), werden Sie das Ende des Vektors verpassen.

0
Benoit
if(allPlayers.empty() == false) {
    for(int i = allPlayers.size() - 1; i >= 0; i--)
    {
        if(allPlayers.at(i).getpMoney() <= 0) 
            allPlayers.erase(allPlayers.at(i));
    }
}

Das funktioniert für mich. Und Sie müssen nicht über Indizes nachdenken, die bereits gelöscht wurden.

0
Dawoon Yi

Die it ++ - Anweisung wird am Ende des Blocks ausgeführt. Wenn Sie also das letzte Element löschen, versuchen Sie, den Iterator zu erhöhen, der auf eine leere Sammlung zeigt.

0

Sie erhöhen it nach dem Ende des (leeren) Containers im Schleifenausdruck der for-Schleife.

0
kbjorklu

Folgendes scheint auch zu funktionieren:

for (vector<int>::iterator it = res.begin(); it != res.end(); it++)
{
  res.erase(it--);
}

Nicht sicher, ob es einen Fehler gibt?