Objekt aus einem vector entfernen!



  • Hallo,

    ich bin schon die ganze Zeit am rumprobieren, aber ich krieg es irgendwie nicht hin.

    ich würde gerne in einer Schleife, ein Objekt aus meinem Vektor entfernen, aber es klappt als nicht...

    ...der betroffene Vektor heisst userArrayUnChange und ist vom Typ CString...

    ...hier ist der Quellcode...

    std::vector<CString> userArrayUnChange;
    std::vector <int>::iterator Iter;
    ...
    ...
    ...
    for (Iter = v1.begin( ) ; Iter != v1.end( ) ; Iter++ )
    {
      cCnt++;
      if (userArrayOld[cCnt] == user) {
        userArrayUnChange.push_back(user);
        userArrayOld.erase(Iter);
        break;
      }
    }
    

    ...also in dieser Aufstellung bringt er schon mal ein Fehler, weil er eben nicht von CString nicht in int konvertieren kann, was auch selbstverständlich ist...aber ich kann doch nicht den Iter auf CString umändern, dann kann ich ihn garnet nicht zählen, wie kann ich dass sonst machen?
    ...hab ich das jetzt falsch verstanden mit dem Iterator?Bin noch ein Newbie 🙂

    gruss,

    chullain



  • Ich glaub Du hast die Iteratoren nicht verstanden.

    1. der Iterator soll ein CString sein (igit, nimm std::string für BEIDE!)
    2. der Code den Du gepostet hast ist schwachsinn.



  • Hallo,

    [msdn]The CStringArray class supports arrays of CString objects. [/msdn]
    Probier's mal mit einem CStringArray.

    Ich blicke bei deinem Codeausschnitt nicht ganz durch 😞

    EDIT: Wir sind hier im C++ Forum, CStringArray ist wohl nicht geeignet ⚠

    MfG



  • 1. der Iterator soll ein CString sein (igit, nimm std::string für BEIDE!)

    ...aber, wie kann ich dann ein bestimmtes Element aus einem Vektor löschen, wenn die erase Methode ein iterator verlangt und wenn der iterator ein CString ist, dann kann ich ihn nicht inkrementieren, wie man das aus dem "schönen" MSDN-Beispiel kennt...

    using namespace std;   
       vector <int> v1;
       vector <int>::iterator Iter;
    
       v1.push_back( 10 );
       v1.push_back( 20 );
       v1.push_back( 30 );
       v1.push_back( 40 );
       v1.push_back( 50 );
    
       cout << "v1 =" ;
       for ( Iter = v1.begin( ) ; Iter != v1.end( ) ; Iter++ )
          cout << " " << *Iter;
       cout << endl;
    

    2. der Code den Du gepostet hast ist schwachsinn.

    ja, gut, ich sehe es ja ein, 🙄 dass dieser Quellcode auf ersten Blick oder in dieser Aufstellung auf das Problem bezogen schwachsinnig erscheint, aber diese Schleife ist ja noch zu anderen Zwecken da, die ich jetzt nicht aufgeführt habe...

    was würdest Du mir empfehlen, wie ich ein bestimmtes Objekt aus einem vektor löschen kann?

    Gruss,

    chullain



  • Der Code ist schon konfus, da wir nicht wissen welchen Typ user, v1 und userArrayOld sind. Ist alles ein wenig durcheinandergewürfelt. Die Grundsätzliche strategie wäre jedoch:

    for(std::vector< std::string >::iterator iter = array.begin(); iter != array.end(); ++iter)
    	if (*iter == vergleichsstring) iter = array.erase(iter);
    

    Wichtig ist, dass du iter nach dem erase neu setzt, da durch das erase die iteratoren ungültig werden. Wenn du einfach alle Elemente mit einem bestimmten Wert löschen willst ist der folgende Weg einfacher:

    array.erase(remove(array.begin(), array.end(), vergleichsstring), array.end())
    


  • Ein RIESEN Dankeschön an Euch alle, hat prima funktioniert...

    ..nur eins würde ich gerne zur Verständlichkeit wissen, also dieser Iterator hat auch selbst eine Tabelle mit einem Index, sonst könnte ich ihn doch nicht inkrementieren, oder?wenn er von Typ String ist...

    gruss,

    chullain



  • der iterator von std::vector ist ein einfacher zeiger vom typ, den du dem vector übergeben hast, also in deinem fall
    Cstring*



  • otze schrieb:

    der iterator von std::vector ist ein einfacher zeiger vom typ, den du dem vector übergeben hast, also in deinem fall
    Cstring*

    Darauf kann uns sollte man sich nicht verlassen. In der aktuellen Version eines Compilers mag das gelten, aber bei anderen Compilern oder in einer neueren Version des gleichen Compilers kann sich das schnell ändern.



  • 1. ich kenn keinen compiler der den vector mit ner eignen iterator klasse implementiert,wenns wieder erwarten anders ist, dann is die version mieserabel(und wieso? ein iterator muss sich wie ein zeiger verhalten,dazu kommt noch, dass der vector den speicher am stück hält, und somit der standardzeiger einfach nur ideal ist,es gibt nichts schnelleres).
    ansonsten is man mit vector<Type>::iterator immer auf der sicheren seite.



  • otze schrieb:

    1. ich kenn keinen compiler der den vector mit ner eignen iterator klasse implementiert,wenns wieder erwarten anders ist, dann is die version mieserabel(und wieso? ein iterator muss sich wie ein zeiger verhalten,dazu kommt noch, dass der vector den speicher am stück hält, und somit der standardzeiger einfach nur ideal ist,es gibt nichts schnelleres).
    ansonsten is man mit vector<Type>::iterator immer auf der sicheren seite.

    Die libstdc++ hat eigene Iteratorklassen. Diese haben auch dies selbe Performance wie Pointer, verhindern aber, dass der Programmierer ungültigen Code schreibt.



  • wenn sie es verhindern, dann is da irgendwo ne if abfrage drin->langsamer.



  • otze schrieb:

    wenn sie es verhindern, dann is da irgendwo ne if abfrage drin->langsamer.

    Nix Abfrage, das macht der Compiler beim kompilieren.



  • das hört sich für mich nah nem echt guten iterator an, aber sag an, wie macht er denn das?

    vector<int> a;
    for(vector<int>::iterator b=a.begin();b<=a.end();++b){
        //do something
    }
    


  • vector<int> a;
    for(vector<int>::iterator b=a.begin();b<=a.end();++b){
        //do something
    }
    

    darauf würde ich mich nicht unbedingt verlassen. ++b besagt nur, dass ich zum nächsten element des vectors gehe. bei einem anderen container können die elemente anders angeordnet sein und womöglich würde die bedingung erfüllt, ohne das alle elemente durchgegangen sind. a.end beschreibt nur das end-element des vectors. wie der zugriff intern geschieht ist erstmal für mich als nutzer nicht relevant. besser wäre es folgendes zu nehmen, damit ist man auf der sicheren seite.

    vector<int> a;
    for(vector<int>::iterator b = a.begin(); b != a.end(); ++b){
        //do something
    }
    

    nochwas, normalerweise ist der vector nicht unbedingt die erste wahl, wenn man elemente häufiger entfernt, da der komplette inhalt des vectors womöglich neu angelegt wird.

    gruss,
    Sebastian



  • es geht hier speziell um std:.vector,hier das passende zitat:

    der iterator von std::vector ist ein einfacher zeiger vom typ, den du dem vector übergeben hast, also in deinem fall Cstring*

    Es geht definitiv nicht um list/map oder andre sachen, ich hab mich ganz klar auf den vector beschränkt, und da is festgelegt, dass ein ++iterator zum nächsten im speicher liegenden element führen muss(und es wurde hier in dem thread noch in keinem beitrag ein anderer container ausser vector genannt)

    desweiteren beschreibt end nicht das end element des vectors, sondern das past-the-end element, was ein großer unterschied ist; das end element ist gültig, das past the end nicht.
    btw: der iterator von vector ist ein random access iterator, ein </<=/>/>= muss gültig sein, und zwar immer. ein for(;a<b;++a) ist äquivalent zu for(;a!=b;++a),unter der voraussetzung, das a nicht größer als b ist, indem fall hat man aber bei a!=b ne endlosschleife-sehr interessant.

    was lernt man daraus a) alle beiträge lesen
    b) etwas von den internen zusammenhängen wissen



  • otze schrieb:

    das hört sich für mich nah nem echt guten iterator an, aber sag an, wie macht er denn das?

    vector<int> a;
    for(vector<int>::iterator b=a.begin();b<=a.end();++b){
        //do something
    }
    

    Was soll er da besonders machen? Außer, dass b<=a.end() gefährlich ist.



  • nich nur gefährlich, sondern der punkt, wo dein iterator sagen MUSS, dass das nich geht, ansonsten is nämlich jeder übertritt möglich, und nix mit fehler erkennung zur compilezeit.



  • otze schrieb:

    nich nur gefährlich, sondern der punkt, wo dein iterator sagen MUSS, dass das nich geht, ansonsten is nämlich jeder übertritt möglich, und nix mit fehler erkennung zur compilezeit.

    Ich schrieb nicht, dass dieser alle Fehler findet. Er erlaubt die geleichen Fehler wie ein Pointer bis auf alle Fehler, die aus der Annahme resultieren, der Iterator müsse ein Pointer sein.

    #include <vector>
    
    int main() {
    	std::vector<int> vec(5);
    	int * p = vec.begin();  // Fehler
    	int * p2 = &*(vec.begin()); // OK
    }
    


  • Hier ist ein Usenet Artikel, der Gründe dafür angibt, warum immer mehr STL Implementierungen darauf verzichten, den vector Iterator als Pointer zu implementieren:

    http://groups.google.de/groups?selm=240720020933594031%25hinnant%40metrowerks.com



  • Ich schrieb nicht, dass dieser alle Fehler findet. Er erlaubt die geleichen Fehler wie ein Pointer bis auf alle Fehler, die aus der Annahme resultieren, der Iterator müsse ein Pointer sein.

    "das beste feature unseres autos ist, dass es sofort explodiert, wenn es als Vase verwendet wird" :p


Anmelden zum Antworten