Qu'advient-il si vous incrémenter un itérateur qui est égal à la fin de l'itérateur d'un conteneur STL
Ce que si je incrémenter un itérateur par 2 quand il pointe sur le dernier élément d'un vecteur? Dans cette question demandant comment régler l'itérateur à un conteneur STL par 2 éléments, deux approches différentes sont proposées:
- soit recourir à un opérateur arithmétique - +=2 ++ ou deux fois
- ou utiliser std::advance()
J'ai testé les deux d'entre eux avec VC++ 7 pour le cas limite lorsque l'itérateur les points sur le dernier élément du conteneur STL ou au-delà:
vector<int> vec;
vec.push_back( 1 );
vec.push_back( 2 );
vector<int>::iterator it = vec.begin();
advance( it, 2 );
bool isAtEnd = it == vec.end(); //true
it++; //or advance( it, 1 ); - doesn't matter
isAtEnd = it == vec.end(); //false
it = vec.begin();
advance( it, 3 );
isAtEnd = it == vec.end(); //false
J'ai vu des fois un conseiller à comparer vector::end() lors de la traversée du vecteur et d'autres contenants:
for( vector<int>::iterator it = vec.begin(); it != vec.end(); it++ ) {
//manipulate the element through the iterator here
}
Évidemment, si l'itérateur est avancé après le dernier élément à l'intérieur de la boucle de la comparaison dans la boucle for la déclaration de la valeur false et la boucle sera heureux de continuer dans un comportement indéterminé.
Puis-je obtenir ce droit que si j'utilise jamais l'avance() ou toute sorte d'opération d'incrémentation sur un itérateur et de faire le point passé le conteneur de la fin, je vais être incapable de détecter cette situation? Si oui, quelle est la meilleure pratique - n'utiliser de telles avancées?
Vous devez vous connecter pour publier un commentaire.
Voici la citation de Nicolai Josuttis livre:
En d'autres termes, la responsabilité de maintenir l'itérateur à l'intérieur de l'aire de répartition est totalement avec l'appelant.
Peut-être vous devriez avoir quelque chose comme ceci:
Vous pouvez surcharge pour
iterator_category<Itr>
estrandom_access_iterator
de faire quelque chose comme ce qui suit:Vous pouvez utiliser la "distance" entre votre iterator () et l'itérateur à vec.begin() et de la comparer avec la taille du vecteur (obtenu par la taille()).
Dans ce cas, votre pour la boucle devrait ressembler à ceci:
Le code que Marijn l'indique est juste un peu de mal (comme curiousguy souligné).
La version correcte de la dernière ligne est:
it > vec.end()
peut être supposé pour être toujours faux.++vec.end()
est un comportement indéterminéJe vous suggère de jeter un oeil à Coup de pouce.Gamme.
Il pourrait être plus sûr à utiliser.
Il sera également en C++0x.
conteneur.fin() -- l'élément juste après la fin-est la seule définis valeur extérieure.
Un activée itérateur est en défaut sur ce qui est essentiellement une gamme d'accès, mais qui n'est pas très utile (surtout que le comportement par défaut est à la fin du programme).
Je pense que la meilleure pratique est "ne pas faire" - soit de vérifier chaque valeur de la variable d'itération (de préférence dans quelque chose d'enveloppé comme un filtre), et ne fonctionnent intéressantes sur les entrées, ou de l'utilisation de l'indice explicitement avec
for(int i = 0; i < vec.size(); i+=2) {...}
Vous pouvez également faire de plus de comparaisons dans votre déclaration:
Je ne sais pas comment ce serait d'effectuer vs Kostas est suggestion, mais il se sent comme il serait mieux pour une petite augmentation. Bien sûr, il serait assez difficile à maintenir pour un grand incrément car vous avez besoin d'une vérification pour chacun, mais il est une autre option.
J'ai vraiment l'éviter si possible. Si vous avez vraiment besoin pour augmenter par tranche de 2 valeurs à un moment, puis envisager d'avoir un vecteur de std::pair ou d'un vecteur d'une structure (struct) avec 2 éléments.
Même si cette question est la moitié d'un an, il pourrait néanmoins être utile de mentionner l'utilisation des opérateurs de comparaison > et < pour vérifier si vous avez réitéré au-delà de la fin (ou le début lors d'une itération à l'arrière) du conteneur. Par exemple: