Question

C’est une question qui explique comment BOOST_FOREACH vérifie sa terminaison de boucle

cout << "Testing BOOST_FOREACH" << endl;
vector<int> numbers; numbers.reserve(8);
numbers.push_back(1); numbers.push_back(2); numbers.push_back(3);
cout << "capacity = " << numbers.capacity() << endl;
BOOST_FOREACH(int elem, numbers)
{
    cout << elem << endl;
    if (elem == 2) numbers.push_back(4); 
}
cout << "capacity = " << numbers.capacity() << endl;

donne le résultat

Testing BOOST_FOREACH
capacity = 8
1
2
3
capacity = 8

Mais qu'en est-il du nombre 4 qui a été inséré au milieu de la boucle? Si je change le type en liste, le nouveau numéro inséré sera itéré. L'opération push_back de vecteur invalidera les pointeurs SI une réallocation est requise, mais cela ne se produit pas dans cet exemple. Je suppose donc que la question est de savoir pourquoi l’itérateur end () ne semble être évalué qu’une fois (avant la boucle) lorsqu’il utilise un vecteur, mais a une évaluation plus dynamique lorsqu’il utilise une liste.

Était-ce utile?

La solution

  

Sous les couvertures, BOOST_FOREACH utilise   itérateurs pour parcourir l'élément   séquence. Avant que la boucle soit exécutée,   l'itérateur final est mis en cache dans un local   variable. Ceci s'appelle le levage, et   c'est une optimisation importante. Il   suppose cependant que la fin   L'itérateur de la séquence est stable. Il   est généralement, mais si nous modifions la   séquence en ajoutant ou en supprimant   éléments pendant que nous itérons sur   on peut finir par se hisser   sur notre propre pétard.

http://www.boost.org/ doc / libs / 1_40_0 / doc / html / foreach / pitfalls.html

Si vous ne voulez pas que l'itérateur end () change, utilisez redimensionner le vecteur plutôt que réserver.

http://www.cplusplus.com/reference/stl/vector/resize /

Notez qu'alors vous ne voudriez pas push_back mais utilisez l'opérateur [] à la place. Mais faites attention à ne pas sortir du terrain.

Autres conseils

La question soulevée dans les commentaires était de savoir pourquoi l'exécution de débogage de Microsoft levait une assertion lors d'une itération sur le vecteur mais pas sur la liste. La raison en est que insert est défini différemment pour liste et vector (notez que push_back est simplement un insérez à la fin de la séquence).

Conformément à la norme C ++ (ISO / IEC 14882: 2003 23.2.4.3, modificateurs de vecteur ):

  

[à l'insertion], si aucune réallocation ne se produit, tous les itérateurs et références précédant le point d'insertion restent valides.

(23.2.2.3, modificateurs de liste ):

  

[insert] n'affecte pas la validité des itérateurs et des références.

Ainsi, si vous utilisez push_back (et que vous êtes sûr que cela ne provoquera pas de réallocation), l'un ou l'autre conteneur peut continuer à utiliser votre itérateur pour effectuer une itération sur le reste de la séquence.

Cependant, dans le cas du vecteur, il est un comportement non défini d'utiliser l'itérateur end que vous avez obtenu avant le push_back .

Ceci est une réponse détournée à la question; c'est une réponse directe à la discussion dans les commentaires de la question.

foreach de boost se terminera s'il est itérateur == nombres.end ()

Attention, appeler Push_back peut / va invalider tous les itérateurs actuels.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top