ALGO25 / BLOG

Când invalidează vectorul un iterator în C++

Înțelege de ce un iterator sau o referință poate deveni invalidă după modificarea vectorului. Separă realocarea de schimbarea pozițiilor.

Un iterator este un obiect folosit pentru a desemna o poziție într-un container și pentru a parcurge elementele. Dacă păstrezi un iterator către un element al unui vector, nu presupune că rămâne valid după orice modificare a vectorului.

Realocarea poate muta toate elementele

Vectorul păstrează elementele într-o zonă continuă. Când adăugarea unui element depășește capacitatea curentă, poate avea nevoie de o zonă mai mare. Elementele sunt mutate sau copiate acolo, iar vechile poziții din memorie nu mai desemnează elementele active ale vectorului.

După o asemenea realocare, iteratorii, pointerii și referințele către elementele vechi sunt invalide. Faptul că vechea adresă pare încă să conțină aceeași valoare într-o rulare nu o face utilizabilă. Nu testa validitatea prin dereferențierea ei.

Lipsa realocării nu garantează orice poziție

La o inserare în interior, elementele de la poziția inserării spre final se deplasează chiar dacă există suficientă capacitate. Pozițiile de la sau după inserare sunt afectate. La ștergere, pozițiile de la sau după zona ștearsă sunt și ele afectate.

Prin urmare, reserve poate reduce realocările, dar nu transformă toate operațiile de modificare în operații care păstrează orice iterator. Trebuie verificată regula operației concrete, nu doar capacitatea disponibilă.

Când adăugarea depășește capacitatea, vectorul poate muta elementele în altă zonă. Iteratorul vechi nu trebuie dereferențiat după realocare.Când adăugarea depășește capacitatea, vectorul poate muta elementele în altă zonă. Iteratorul vechi nu trebuie dereferențiat după realocare.Mărește schema ↗

Păstrează sensul poziției, nu doar numărul ei

Uneori poți păstra un indice și poți obține din nou elementul după modificare. Totuși, dacă ai inserat înaintea lui, indicele vechi desemnează alt element. Un indice este o poziție în secvență, nu identitatea permanentă a unui obiect.

Pentru o parcurgere care modifică vectorul, stabilește explicit ce element urmează să fie vizitat. După erase, operația întoarce un iterator potrivit pentru continuare. După adăugări care pot realoca, recalculează iteratorii necesari din containerul actual.

Cum verifici problema fără comportament invalid

Urmărește size și capacity înainte și după adăugare, dar nu accesa iteratorul vechi dacă operația l-a invalidat. Construiește separat un test cu inserare în mijloc și unul cu adăugare la final. Ele au reguli diferite pentru pozițiile afectate.

Pentru regulile precise, consultă modificarea vectorului în specificația C++. Recapitulează iteratorii, inserarea și pointerii.

Întrebări frecvente

Când invalidează push_back iteratorii unui vector?

Dacă adăugarea provoacă realocarea, iteratorii, pointerii și referințele către elemente devin invalide. Fără realocare, pozițiile elementelor existente rămân valide, dar vechiul iterator de sfârșit este invalidat.

Reserve garantează că orice iterator rămâne valid?

Nu pentru orice modificare. O capacitate suficientă poate evita realocarea la adăugări, dar ștergerile și inserările au propriile reguli de invalidare. Verifică operația concretă.

Cum evit folosirea unui iterator după o posibilă realocare?

Nu reutiliza iteratorul vechi. Reobține poziția din container după modificare sau păstrează un indice când operația și semnificația indicelui permit acest lucru.