34 votes

Comment procédez-vous en arrière dans une liste STL?

Je suis en train d'écrire quelques croix-plate-forme de code entre Windows et Mac.

Si la liste::end () retourne un itérateur qui traite de l'emplacement de réussir le dernier élément dans une liste" et peut être vérifié lors de la traversée d'une liste, quel est le meilleur chemin à parcourir à l'envers?

Ce code workson le Mac mais pas sur Windows (ne peut pas décrémenter delà du premier élément):

list<DVFGfxObj*>::iterator iter = m_Objs.end();
for (iter--; iter!=m_Objs.end(); iter--)// By accident discovered that the iterator is circular ?
{
}

cela fonctionne sur Windows:

list<DVFGfxObj*>::iterator iter = m_Objs.end();
    do{
        iter--;
    } while (*iter != *m_Objs.begin());

Est-il un autre chemin à parcourir vers l'arrière, qui pourrait être mis en œuvre dans une boucle for?

60voto

Ferruccio Points 51508

Utilisez reverse_iterator au lieu d'itérateur. Utilisez rbegin () & rend () au lieu de begin () & end ().

Une autre possibilité, si vous aimez utiliser la macro BOOST_FOREACH, est d'utiliser la macro BOOST_REVERSE_FOREACH introduite dans Boost 1.36.0.

16voto

mmocny Points 3655

Le meilleur/la plus simple façon d'inverser itérer une liste (comme déjà dit) à utiliser reverse itérateurs rbegin/rend.

Cependant, je tiens à préciser que d'inverser les itérateurs sont mis en œuvre de stocker le "courant" iterator position de hors-en-un (au moins sur l'implémentation GNU de la bibliothèque standard).

Ceci est fait pour simplifier la mise en œuvre, dans l'ordre de la plage dans le sens inverse à la même sémantique que d'une gamme de l'avant [début, fin) et [rbegin, rené)

Ce que cela signifie, c'est que le déréférencement d'un itérateur, implique la création d'un nouveau temporaire, puis le décrémenter, à chaque fois:

  reference
  operator*() const
  {
_Iterator __tmp = current;
return *--__tmp;
  }

Ainsi, *référence à un reverse_iterator est plus lent que la normale itérateur.*

Toutefois, Vous pouvez à la place utiliser le itérateurs bidirectionnels pour simuler l'inverse de l'itération de vous-même, évitant ce traitement:

for ( iterator current = end() ; current != begin() ; /* Do nothing */ )
{
    --current; // Unfortunately, you now need this here
    /* Do work */
    cout << *current << endl;
}

Des essais ont montré que cette solution soit ~5 fois plus rapide pour chaque déréférencement utilisés dans le corps de la boucle.

Remarque: ce Test n'a pas été fait avec le code ci-dessus, en tant que std::cout aurait été le goulot d'étranglement.

À Noter également: le "mur de l'horloge temps" la différence était d'environ 5 secondes avec un std::la taille de la liste des 10 millions d'éléments. Donc, de façon réaliste, à moins que la taille de vos données est très grande, il suffit de coller à rbegin() rend()!

13voto

Anthony Cramp Points 1665

Vous voulez probablement les itérateurs inversés. De mémoire:

 list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin();
for( ; iter != m_Objs.rend(); ++iter)
{
}
 

5voto

steffenj Points 3704

Cela devrait fonctionner:

 list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin();
for (; iter!= m_Objs.rend(); iter++)
{
}
 

5voto

ejgottl Points 2178

Comme déjà mentionné par Ferruccio, utilisez reverse_iterator:

 for (std::list<int>::reverse_iterator i = s.rbegin(); i != s.rend(); ++i)
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X