bestimmtes Element in std::vector löschen



  • Hi Leute,

    ich habe mir eine Klasse geschrieben, die ein paar Personendaten speichert. Nun möchte ich, dass ein Element anhand des Indexes gelöscht wird. Ich habe da auch schon in der STL-Doku nachgesehen und bin da auf die Methode remove gestoßen. Mit dieser Methode, kann man ja ein Element aus der dem Vector löschen, aber anhand eines Wertes. Da dies aber für mein Programm eher schlecht ist, da es ja mehrere Personen gibt, die zum Beispiel den Namen Müller haben, kann ich das nicht so machen, denn dann würden ja alle, die den Namen Müller ihr Eigen nennen, gelöscht werden.

    Gibt es eine Möglichkeit, dies mit Hilfe des Indexes zu machen? Wäre nett, wenn ihr mir da helfen könntet. Danke schonmal...

    MfG Apo





  • Okay..., danke. Werde es heute mal ausprobieren.

    MfG Apo



  • iterator erase(iterator pos)
    

    Löscht in einem Vektor das Element an der Oterator-Pos. pos und liefert die Iterator-Pos hinter pos zurück.
    bzw.

    iterator erase(iterator anf, iterator end)
    

    Löscht in einem Vektor die im Bereich [anf,end[ liegenden Elemente und liefert die Iterator-Pos nach anf zurück.
    http://www.cplusplus.com/reference/stl/vector/erase.html

    allerdings sind diese methoden u.U. sehr zeitintensiv, da ein vector sich dadurch auszeichnet, dass alle elemente an "einem Stück" im speicher liegen. löscht du in der mitte welche, dann müssen die dahinterligeneden "nach vorne" kopert werden.

    PS: es gibt im standard keine erase funktion, die einen Index übernimmt



  • Trotzdem ist es die einzig vernünftige Möglichkeit. Man kann ja folgendes machen

    vect.erase(vect.begin()+index);
    


  • Braunstein schrieb:

    Trotzdem ist es die einzig vernünftige Möglichkeit.

    hab ich auch nie angezweifelt...



  • Ich sagte das bloß weil hier auch remove auftauchte. remove fand ich schon immer etwas missdeutlich bennant. Immerhin entfernt es ja die Elemente nicht aus der Sequenz sondern ordnet sie nur hinten an.



  • remove() "löscht" die Elemente schon - mangels Zugriff auf die internen Containerdaten halt etwas unkonventionell durch Überschreiben (btw, vector::erase() macht auch nichts anderes als die Lücken durch nachfolgende Elemente aufzufüllen - es merkt sich nur, welcher Bereich seiner Daten gültige Elemente enthält). Und was nach dem Aufruf hinter der (verkürzten) Sequenz steht, ist undefiniert (und dort landen wohl in den seltensten Fällen die gelöschten Elemente).



  • Nun ja. AFAIK wird end() und size() aber nicht neu gesetzt und das könnte bei der Weiterverwendung Probleme gegeben. Im Standard steht nur "Eliminates all the elements referred to by iterator..."
    Ich glaube in "more exceptional C++ Item2" stand, dass man, um eine wirkliche Löschung zu erzielen, das Ganze mit erase kombinieren muss.
    Ich habe auch nirgendwo gefunden, dass nach remove der Zugriff auf Elemente hinter dem neuen Ende undefiniertes Verhalten erzeugt.



  • Braunstein schrieb:

    Nun ja. AFAIK wird end() und size() aber nicht neu gesetzt und das könnte bei der Weiterverwendung Probleme gegeben.

    Ja, das gehört zu den Möglichkeiten, die Zugriff auf die Datenstruktur benötigen - und diesen Zugriff hat der Algorithmus nicht (schließlich soll er auch mit Arrays und eigenen Klassen arbeiten können - zumindest erstere haben kein size(), was man korrigieren könnte). Darum liefert es auch einen Iterator auf die neue Endposition zurück - mit der kannst du auch weiterarbeiten.

    Ich habe auch nirgendwo gefunden, dass nach remove der Zugriff auf Elemente hinter dem neuen Ende undefiniertes Verhalten erzeugt.

    Ich glaube, das war auch "nur" implementation defined - aber da müsste ich nachsehen.



  • Ok, das ist logisch.
    Zum Löschen von Elementen aus einem Container gehört für mich einfach die Anpassung von size() etc. dazu.



  • CStoll schrieb:

    vector::erase() macht auch nichts anderes als die Lücken durch nachfolgende Elemente aufzufüllen - es merkt sich nur, welcher Bereich seiner Daten gültige Elemente enthält).

    das hoffe ich mal nicht. denn aufgrund der C-Syntax bei MPI versende ich std::vector-en immer via MPI::Send(&vec[0], 10,...). und auch sonst arbeite ich oftmals direkt mit den adressen. und bis data hatte ich hier weder mit dem gcc/Intel compiler/minGW oder cl probleme

    spräche auch gegen die hohe performance von vectoren. für löschen innerhalb von containern soll man eh besser listen/maps der ähnliches verwenden.

    ein nicht representativer test bestätigt zumindest meine aussage:

    int main()
    {
    int main()
    {
       std::vector<int> vec;
       for(int i=0; i<8; i++) vec.push_back(i);
       for(int i=0; i<8; i++) std::cout<< (&vec[0])[i]<<" ";
       std::cout<<std::endl;
       vec.erase(vec.begin()+2);
       vec.push_back(9);
       for(int i=0; i<8; i++) std::cout<< (&vec[0])[i]<<" ";
    
       return 0;
    }
    

    ausgabe:

    0 1 2 3 4 5 6 7
    0 1 3 4 5 6 7 9

    bei wem dies nicht so rauskommt, der sage mir bitte bescheid.



  • Ich hab mal kurz in vector::erase in meiner dinkumware reingeschaut.
    Dort wird folgendes gemacht.
    - Die Daten von hinten über den zu löschenden Wert kopiert.
    - destroy für das letzte Element aufgerufen
    - end angepasst.
    Die Daten bleiben also hintereinander.



  • ja, ich hab auch bei der STL-Implementierung für den cl von VS8 nachgeschaut. und im "C++ STL - verstehen, anwenden, erweitern" von gallileo steht es auch so. aber das mus snicht heissen, dass der standard das explizit so fordert... wäre nur interessant zu wissen.



  • Der Standard scheint das nicht zu fordern. Jedenfalls nicht in der Version die ich habe (2003 23.2.4.3).



  • Braunstein schrieb:

    Der Standard scheint das nicht zu fordern. Jedenfalls nicht in der Version die ich habe (2003 23.2.4.3).

    dacht mir sowas... schade...



  • Der Standard fordert seit der 2003er zumindest, dass &vec[0] gültig ist und ein Zeiger auf den Anfang der gesamten Sequenz ist. Ich hab jetzt keine Lust die Stelle rauszusuchen, das Thema kam in letzter Zeit aber häufiger. In einem der entsprechenden Beiträge gibts auch den Standardauszug.



  • Ich raff net so ganz, was ihr hier diskutiert, aber bei mir funktioniert das mit erase wunderbar. Alle nachfolgenden Daten werden wunderbar beibehalten und es läuft auch wunderschön schnell.

    Danke nochmal, wegen dem Hinweis auf erase. 😉

    MfG Apo



  • LordJaxom schrieb:

    Der Standard fordert seit der 2003er zumindest, dass &vec[0] gültig ist und ein Zeiger auf den Anfang der gesamten Sequenz ist. Ich hab jetzt keine Lust die Stelle rauszusuchen, das Thema kam in letzter Zeit aber häufiger. In einem der entsprechenden Beiträge gibts auch den Standardauszug.

    hört sich doch schonmal ut an. aber der index operator muss auch bei allen anderen elementen korrekt funktionieren. und das meine ich, dass der sinn eines vectors flöten geht, wenn man bei vec[8] intern die "8" verbiegen muss, da man mal was gelöscht hat und die interne reihenfolge nicht mehr der "externen" entspricht. verkompliziert die interne sache einfach und kostet performance.



  • Meint ihr das aus 23.2.4 1

    ... Storage management is handled automatically, though hints can be given to improve efficiency. The elements of a vector are stored contiguously, meaning that if v is a vector<T, Allocator> where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().


Anmelden zum Antworten