Vector iterator: Letztes element löschen



  • Brumm!

    Ist es wirklich so umständlich, per vector iterator das letzte Element zu löschen?

    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main()
    {
    	vector<int> v;
    	vector<int>::iterator i;
    
    	v.push_back(2);
    	v.push_back(4);
    	v.push_back(6);
    	v.push_back(8);
    	v.push_back(10);
    
    	for(i = v.begin(); i != v.end(); )
    	{
    		// 4 und 10 löschen
    		// Beim letzten Element zeigt 'i' abschließend auf v.end()
    		// Daher darf man ++i nicht in den Schleifenkopf setzen, sonst
    		// würde 'i' zum Schluss auf v.end() + 1 zeigen
    		if(*i == 4 || *i == 10)
    			i = v.erase(i);
    
    		// Ausgabe
    		// Hier muss man leider prüfen, ob 'i' noch nicht auf das Ende zeigt
    		// Das passiert ja nach dem Löschen des letzten Elements
    		if(i != v.end())
    			cout << *i << endl;
    
    		// Hier muss leider schon wieder geprüft werden
    		// Vergammelter Honig aber auch!
    		if(i != v.end())
    			++i;
    	}
    }
    

    Ich bin nur ein armer Bär 😞



  • v.pop_back()
    //oder
    v.erase(v.end()-1);
    


  • Dann müsste ich aber doch wieder extra abfragen, ob das aktuelle Element das letzte ist und dann halt pop_back() aufrufen, ansonsten erase...

    Ist doch auch wieder Bitterhonig!



  • Winnie-the-Pooh schrieb:

    Dann müsste ich aber doch wieder extra abfragen, ob das aktuelle Element das letzte ist und dann halt pop_back() aufrufen, ansonsten erase...

    Ist doch auch wieder Bitterhonig!

    😕



  • Die letzten beiden Abfragen kannst Du auf jeden Fall schonmal zu einer zusammenfassen. Ansonsten schau Dir mal remove_if an, das ist auch schneller... allerdings ändert es evtl. die reihenfolge der elemente.



  • Winnie-the-Pooh schrieb:

    Dann müsste ich aber doch wieder extra abfragen, ob das aktuelle Element das letzte ist und dann halt pop_back() aufrufen, ansonsten erase...

    Verwende immer den Container der am ehesten deinen Anwendungsfall entspricht.

    std::vector ist z.B. nicht optimal für häufiges wahlfreies Löschen, aber dafür sehr schnell beim wahlfreien Zugriff.

    @Tachyon: Ist "v.end()-1" wirklich immer definiert?

    cu André



  • if ( zu_löschen )
        i = v.erase( i );
    else
        ++i;
    

  • Mod

    Das eigentliche Problem ist doch, dass nach einer Löschoperation einfach angenommen wird, dass das folgende Element nicht zu löschen ist und nur für diese Folgeelement bedarf es dieser zusätzlichen Prüfung (der Existenz), andernfalls wäre die Schleife ja schon beendet worden. Ohne diesen künstlichen Überspringer, der fehlerhaft sein dürfte, ergibt sich einfach:

    for(i = v.begin(); i != v.end(); )
        {
            if(ist_zu_loeschen(*i))
            {
                // Löschen und Iterator auf Folgelement bzw. Ende
                i = v.erase(i);
            }
            else
            {
                // Eine Prüfung auf i != v.end() erübrigt sich, bei i == v.end() wäre die Schleife schon beendet worden
                // (wenn wir in diesen Zweig des if-Statements gelangt sind, wurde v wärend dieses Iterationszyklus' nicht verändert
                // mithin wäre eine Prüfung i != v.end() äquivalent zu der, die bereits im Schleifenkopf durchgeführt wurde und somit überflüssig)
                cout << *i << endl;
                ++i;
            }
        }
    


  • asc schrieb:

    @Tachyon: Ist "v.end()-1" wirklich immer definiert?

    Bei 'nem leeren Vektor nicht, aber das trifft auch auf pop_back() zu.



  • 👍

    So ist's gut.



  • Alternativ gehts auch so:

    //Functor fuer find_if
    struct FindCondition
    {
    
        FindCondition(int val):m_val(val){}
        bool operator()(int val){return val == m_val;}
        int m_val;
    };
    
    //...
    //nach Wert suchen (hier 2)
    iter = std::find_if(l.begin(), l.end(), FindCondition(2));
    //loeschen, wenn gefunden
    if(iter !=  l.end())
    {
        l.erase(iter);
    }
    

Log in to reply