Objekte in Container löschen



  • Hallo Zusammen,

    ich habe Objekte in einem Container (map) und leere den Container mit container.clear(); Ruft der Container für jedes Objekt den Destructor auf, oder muss ich das selber machen?

    Vielen Dank schon mal,
    M. Incani



  • Hallo

    Ja clear löscht auch die einzelnen Elemente des Containers. Allerdings must du beachten, das bei Pointern als Elementen nicht die Instanzen gelöscht werden.

    std::vector<MyClass> test1; // Instanzen werden bei clear gelöscht
    std::vector<MyClass*> test1; // Instanzen werden bei clear nicht gelöscht
    

    bis bald
    akari



  • Ja, es werden, wie bei den anderen STL-Containern auch, jeweils die Destruktoren aufgerufen. Nur wenn du Zeiger verwendest, dann mußt du die Objekte selbst löschen.



  • Ich habe auch mal eine Frage zum Container map:

    Kann man irgendwie auch einzelne Elemente aus der map löschen? In Python geht das einfach, aber in C++ scheint es einfach nicht zu gehen oder ich finde nicht die entsprechenden Hinweise wie es funktionieren soll.

    Ich habe eine map erstellt die als Key eine Zahl speichert und als value die Anzahl. Der Key geht dabei von 1..n, also sowas hier:

    map<int,int> vals;
    

    dann eine for Schleife die Werte analysiert und immer, wenn der Wert vorhanden ist, ihn inkrementiert oder neu anlegt:

    for (int i = 1; i < irgendwas(); i++)
        vals[i] = vals[i] ? vals[i] += 1 : 1;
    

    Das funktioniert auch, nun möchte ich aber alle Werte, wo die Anzahl kleiner 10 ist, aus der Map löschen. Wie kann ich das denn machen?



  • Hallo

    Die Basisfunktion zum Löschen von Elementen ist std:🗺:erase

    bis bald
    akari



  • Hallo, das scheint leider nicht so ganz zu funktionieren, wahrscheinlich weil die Map sofort neu sortiert wird oder jedenfalls der Pointer nicht mehr gültig ist?

    Hier mal meine Testausgabe nach Löschen der Werte mit einer kleineren Anzahl als 10 (nach dem Muster ZAHLENWERT:ANZAHL):

    4:203 - 19:155 - 25:3 - 26:32 - 29:2 - 30:45 - 31:584 - 33:1 - 35:10 - 36:829 - 40:25 - 41:12 - 56:11 - 64:27 - 66:39 - 77:26 - 81:1 - 88:25 - 90:268 - 93:25 - 95:29 - 97:14 - 99:79 - 113:1 - 117:12 - 121:236 - 125:5 - 127:18 - 128:84 - 129:16 - 133:11 - 137:35 - 141:12 - 143:12 - 145:8 - 155:1187 - 157:2 - 159:33 - 160:157 - 167:27

    Wie man sieht sind immer noch Werte dabei, die weniger als 10mal vorkommen, z.B. die 113 oder die 125...

    Meine Schleife zum Löschen sieht folgendermaßen aus:

    for (map<int,int>::iterator it = labelValues.begin(); it != labelValues.end(); ++it)
    {
        if (it->second < 10)
            labelValues.erase(it);
    }
    


  • Ja, beim erase() wird der Ziel-Iterator ungültig - aber als Gegenleistung liefert die Methode dir einen Iterator auf die nächste gültige Position:

    for (map<int,int>::iterator it = labelValues.begin(); it != labelValues.end();)
    {
        if (it->second < 10)
            it=labelValues.erase(it);
        else
            ++it;
    }
    


  • Ich habe heute wohl einen schlechten Tag, kapiere nicht was ich schon wieder falsch mache, aber ich kann wohl den Iterator nicht zuweisen:

    eyelocator.cpp:289: error: no match for ‘operator=’ in ‘it = ((EyeLocatorPriv*)this)->EyeLocatorPriv::labelValues. std::map<_Key, _Tp, _Compare, _Alloc>::erase [with _Key = int, _Tp = int, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, int> >](it)’

    Ich habe dann den Iterator mal außerhalb definiert, aber auch dann der selbe Fehler. Der Code ist genau der selbe den du eben gepostet hast...



  • Ok mit einer Map scheint das einfach nicht zu gehen, denn dann liefert erase() nur void. Kann ich vielleicht versuchen eine andere Lösung zu nutzen?
    Ich brauche einen Container der einem Wert einen anderen zuordnen kann. Mir fällt da nur eine Map ein...



  • *grübelt* Stimmt, das könnte ein Problem sein - hatte das mit list::erase() verwechselt.

    Eine Möglichkeit wäre es noch, den Iterator erst zu inkrementieren und danach die alte Position zu löschen:

    for (map<int,int>::iterator it = labelValues.begin(); it != labelValues.end();)
    {
        if (it->second < 10)
            labelValues.erase(it++);//Post-Inkrement gibt den ursprünglichen Iterator zurück
        else
            ++it;
    }
    


  • ok das scheint zu gehen, hoffen wir mal das er auch alle Zahlen richtig löscht und nicht doch einige falsch herausfummelt.
    So ganz kapiere ich es aber nicht. Wie kann denn Post-Inkrement noch gehen wenn der Iterator ab dann ungültig ist?



  • Der Post-Inkrement-Operator wird vor dem Funktionsaufruf ausgeführt - und liefert eine (ältere) Kopie deines Iterators zurück. Darum zeigt it während des Aufrufs auch nicht mehr auf das zu löschende Element (und andere Elemente werden von erase() nicht ungültig gesetzt).

    Im Prinzip sieht das so aus:

    iterator temp = it++;
    labelValues.erase(temp);
    
    // oder - op++ auseinandergenommen:
    iterator temp = it;
    ++it;
    labelValues.erase(temp);
    

    (temp wird am Ende der erase()-Anweisung wieder zerstört, also stört es niemanden, daß er nicht mehr auf ein gültiges Map-Element zeigt)



  • Ah danke schön für die Erklärung und die Lösung!!
    🙂



  • Oh ich habe doch noch eine Frage, ihr merkt ich kenne mich noch nicht so gut in C++ aus, komme von Python her.

    Ich habe nun eine Datenstruktur (CImg) und diese Map und will nun einfach für jeden Bildpunkt schauen, ob der Wert in der Map vorkommt.

    In Python würde ich es so machen (pseudocode):

    if (img(x,y) in map.keys())
        // setze auf eine Farbe
    else
        // setze auf 0
    

    Wie kann man das denn nun in C++ umsetzen?



  • mit

    if (mymap.find(mykey) != mymap.end()) //...
    

    Erlaeuterung: map::find(const key_type& x) liefert einen iterator auf den Wert, dessen key x ist. Wenn x in der map nicht vorhanden ist, liefert find() einen iterator hinter dem letzten element, genau wie map::end().



  • Cool das geht, vielen vielen Dank. So langsam komme ich mit C++ auch klar, ist halt komplett anders, vor allem die Pointer-Sachen...


Anmelden zum Antworten