2010-12-07 36 views
1

Disons que j'ai ce code:Comment garder un itérateur déréférenciable lorsque son vecteur est ajouté?

std::vector<Object*> objects; 
std::vector<Object*>::iterator iter; 
for (iter = objects.begin(); iter != objects.end(); iter++) { 
    if (condition) 
     objects.push_back(new Object()); 
} 

Toutefois, lorsque push_back se produit, iter devient undereferenceable. Sans réinitialiser iter, comment puis-je le garder dereferenceable? Si je dois le réinitialiser, y a-t-il un moyen facile de le faire pour qu'il revienne là où il était avant?

+0

Comme une note de côté, Theres un bug logique possible dans cette idée que si vous ajoutez 'objets à la fin alors que nous parcourons, il est possible que vous pourriez entrer dans une boucle infinie que de plus en plus d'objets sont ajoutés et itération ne se termine jamais (theres toujours un autre objet à itérer à!) – MerickOWA

Répondre

5

Je vous recommande de simplement y accéder par index. Cela élimine complètement le problème.

0

Vous devrez résulter en une ancienne boucle for avec des indices numériques. Soit cela, ou reserve() le vecteur avant que la boucle ne s'exécute pour garantir qu'il ne sera pas redimensionné.

De même, pointeurs bruts? Srsly.

0

L'itérateur ne devient invalidé que si le vecteur doit réaffecter plus de mémoire.

Pour éviter la réaffectation de la mémoire pré-allouer toute la mémoire dont vous avez besoin avec réserve() (en supposant que vous connaissez cette taille lorsque vous allouez le vecteur).

La solution la plus simple conserve une référence indirecte au membre (un index dans le tableau).

1

Si vous devez absolument utiliser itérateurs pour cela:

std::vector<Object*> objects; 
std::vector<Object*> newObjects; 
std::vector<Object*>::iterator iter; 
for (iter = objects.begin(); iter != objects.end(); ++iter) 
{ 
    if (condition) 
    { 
     newObjects.push_back(new Object()); 
    } 
} 

std::copy(newObjects.begin(), newObjects.end(), back_inserter<vector<Object*> >(objects)); 
0

§23.1/11:

Sauf indication contraire (soit explicitement ou en définissant une fonction en termes d'autres fonctions) , invoquant une fonction de membre du récipient ou passer un récipient comme un argument à une fonction bibliothèque ne doit pas invalider itérateurs, ou modifiez les valeurs de, objets dans ce conteneur.

Cependant, il n'est pas explicitement spécifié que std :: vector :: push_back invalide tous les itérateurs.

+0

Certains tests que j'ai fait confirment que le push_back peut en effet invalider un itérateur. – Oswald

+0

La raison en est probablement qu'un vecteur est une séquence et pour une séquence s, s.push_back (x) est défini comme s.insert (s.end(), x) et std :: vector :: insert est autorisé à invalider les itérateurs. – Oswald

0

Comme la plupart des autres réponses le disent déjà, vous devriez probablement accéder au vecteur par index dans ce cas.

Cependant, pour être complet: std::list itérateurs ne sont pas ce « problème ». Donc, en utilisant list au lieu de vector est une solution possible.