Pointer *it Speicherleck?



  • Hallo,

    s. Code untenstehend

              for(auto it = items.begin(); it != items.end(); ++it){
                    map <string, string> hunt;
                    string url = *it;
                    hunt["url"] = url;
                    hunt["short"] = BIN[url]["short"];
                    links.push_back(hunt);
                }
    

    Muss ich den Pointer *it explizit freigeben (delete) oder passiert das automatisch?
    c++ 201402

    MFG


  • Gesperrt

    Du meinst den string url... aber das passiert alles automatisch.



  • it ist kein Pointer, sondern ein Iterator.



  • @Belli

    ist ein iterator kein Pointer?

    MFG



  • @_ro_ro Was von begin/end zurückgegeben wird sind entweder spezielle Iterator-Objekte oder maximal nicht-besitzende Pointer. Beides muss man nicht explizit freigeben.



  • @_ro_ro
    Ja, ein Iterator ist kein Pointer.



  • @Finnegan sagte in Pointer *it Speicherleck?:

    @_ro_ro Was von begin/end zurückgegeben wird sind entweder spezielle Iterator-Objekte oder maximal nicht-besitzende Pointer. Beides muss man nicht explizit freigeben.

    OK, danke. Hab' mittlerweile auch begriffen, daß ich den Iterator gar nicht brauche weil ich mit auto item:items den Wert direkt bekomme. Mächtig gewaltig c++ mal sehen wie das weitergeht 😉

    Danke Euch!!!



  • @_ro_ro sagte in Pointer *it Speicherleck?:

    @Belli

    ist ein iterator kein Pointer?

    Nein. diese verhalten sich nur ähnlich wie Zeiger, besonders was Dereferenzieren und Zugriff auf benachbarte Elemente angeht. Das ist so gewollt, dass die ähnlich zu benutzen sind. Man könnte sogar eine Container-Klasse bauen, die für begin/end Pointer zurückgibt, wenn die zugrundeliegende Datenstruktur es erlaubt, dass man die Elemente einfach über Pointer-Arithmetik iteriert. Ich glaube aber nicht, dass das eine Implemetierung der Standardbibliothek so macht, obwohl ich mir vorstellen kann, dass das z.B. bei std::array, std::vector und std::string möglich wäre. Iteratoren können durchaus Pointer sein, aber im Allgemeinen stimmt das natürlich nicht.

    Edit: GCC (bzw. hier libstdc++, die Standardbibliothek von GCC) scheint für std::array tatsächlich mit Pointern als Iteratoren zu arbeiten: https://godbolt.org/z/fjd6n7z71.Pi in der Ausgabe steht hier für int* (Stichwort "Name Mangling").



  • @Finnegan sagte in Pointer *it Speicherleck?:

    dass man die Elemente einfach über Pointer-Arithmetik iteriert. Ich glaube aber nicht, dass das eine Implemetierung der Standardbibliothek so macht, obwohl ich mir vorstellen kann, dass das z.B. bei std::array, std::vector und std::string möglich wäre.

    MIr ist da eine Sache für std::vector oder std::string aufgefallen.

    Nehmen wir an, ein Iterator wäre als Pointer implementiert. Und nehmen wir ferner an, wir nutzen den Iterator in der Form:

    std::vector<int> vec{1, 2, 3, 4};
    auto it = vec.begin();
    
    while(it != vec.end())
    {
      if (Foo(it))
        vec.push_back(5);
      //...
      it++;
    }
    

    Dann würde der Code abstürzen, wenn vec.push_back(5); oft aufgerufen wird. In diesem Fall allokiert nämlich std::vector neuen Speicher, kopiert die alten Daten in den neuen Speicher und löscht den alten Speicher. Dadurch würde der Iterator ungültig und der Iterator-Pointer zeigt auf Datenmüll.

    Deswegen, so schätze ich, macht ein Index bei Random Access Iteratoren mehr Sinn.



  • @Quiche-Lorraine sagte in Pointer *it Speicherleck?:

    Dann würde der Code abstürzen, wenn vec.push_back(5); oft aufgerufen wird. In diesem Fall allokiert nämlich std::vector neuen Speicher, kopiert die alten Daten in den neuen Speicher und löscht den alten Speicher. Dadurch würde der Iterator ungültig und der Iterator-Pointer zeigt auf Datenmüll.

    Deswegen, so schätze ich, macht ein Index bei Random Access Iteratoren mehr Sinn.

    Ja, ich denke sowas kann man mit speziellen Iterator-Klassen flexibler umsetzen, so dass diese auch bei solchen Operationen weiterhin gültig bleiben. Allerdings invalidiert ein vector::push_back existierende Referenzen und Pointer in diesem Fall - das ist also hier UB:

    If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only the end() iterator is invalidated.

    https://en.cppreference.com/w/cpp/container/vector/push_back

    Das dürfte auch so im Standard stehen. Ich denke aber, man könnte mit Iterator-Objekten durchaus eine vector-Klasse implementieren, welche die Iterator-Gültigkeit auch bei Reallokation garantiert.


Anmelden zum Antworten