Debug Assertion: Vector iterators incompatible.



  • Hallo!

    vector <int> vi;
    	vi.push_back(0);
    	vector <int>::iterator it = vi.begin();
    
    	int num = *it;
    	it = vi.erase(it);
    	if ( it == vi.end() )
    		cout << "This is THE END." << endl; // OK
    
    	vi.push_back(num);
    
    	if ( it != vi.end() ) // Debug Assertion: Vector iterators incompatible.
    		cout << "This is not THE END." << endl;
    

    Ich bekomme bei der Ausführung des Codes die Meldung:

    Debug Assertion: Vector iterators incompatible.

    Warum eigentlich und wie geht es richtig?
    Meine Vermutung ist: nach Ausführung von

    vi.push_back(num);
    

    wird der angeforderte Iterator ungültig.


  • Administrator

    vectorincompatibility schrieb:

    Meine Vermutung ist: nach Ausführung von

    vi.push_back(num);
    

    wird der angeforderte Iterator ungültig.

    Das ist korrekt. Jegliche Veränderung an eine std::vector Container führt zur Invalidierung aller Iteratoren auf diesen Container.

    Kannst du auch sehr schön hier nachlesen:
    http://magazin.c-plusplus.net/artikel/Aufbau%20der%20STL%20-%20Teil%201%3A%20Container

    Wie man es richtig macht? Nun, durch ein push_back kann it nicht plötzlich auf das Ende verweisen, daher ist diese Kontrolle unnötig.

    Grüssli



  • Stimmt, in diesem Fall gibts kein Ende, aber ich habe das Problem 'umzingelt' und ein Minimalbeispiel gepostet, wobei es auf folgendes hinausläuft:

    Ich möchte nen Vector von Anfang bis Ende durchlaufen und
    an beliebiger Stelle Elemente mit erase entnehmen und je nach Bedingung diese Elemente entweder in den Vector mit push_back nach hinten zurückschieben(Position ändern), oder gelöscht lassen.
    (In meinem post habe ich das 'gelöscht lassen' weggelassen.)
    Nach push_back oder erase soll mit dem nächsten Element weiter gemacht werden. Ist der Iterator am Ende, soll wieder am Anfang weiter gemacht werden, bis der Vector leer ist.

    Könntest du mir bitte einen Tipp geben, wie man das machen kann?



  • Du brauchst einfach nur ne deque. 💡 😋

    deque<Job> todo;
    while(!todo.empty()){
      Job& j=todo.pop_front();
      j.run();
      if(...)
        todo.push_back(j);
      todo.pop_front();
    }
    

    (eigentlich riecht die aufgabe nach einem intrisiver nichtleeren doppelt verketteter ring, aber deque ist gut genug)



  • Da kannst du dir ja eine schöne Endlosschleife bauen 😉
    Aber warum schiebst du die Elemente nicht anstatt an das Ende in einen neuen Vector? Und wenn der Ursprungsvector leer ist einfach per swap die Elemente umfüllen?


  • Mod

    Also das klingt ganz klar nach einem Fall für std::list. Da hat man dann auch nicht das Problem, dass die Iteratoren ungültig werden.



  • Wollte mir grade was zurechtbauen:

    // Pseudocode
    vector v, i=0, size = v.size(),
    L: solange size != 0:
        - elem e = erase v.at(i)
        - wenn vector nicht leer:    // Lücke auffüllen
             für alle j = i && j < v.size() -1:    
             v[j] = v[j+1]  
        - v.push_back(e) oder nicht     
        - wenn i == size
            size = v.size()
            i = 0
           goto L
    

    Aber jetzt habe ich ja viele Tipps bekommen, denen ich nachgehen werde.
    Danke erstmal!


Anmelden zum Antworten