L’assertion «vecteur iterator + décalage hors limites» est-elle utile?

Ce programme parfaitement bon échoue en mode débogage dans Visual Studio 2013:

#include  #include  #include  using namespace std; void main() { vector v = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3}; for (auto iFrom = v.cbegin(), iTo = iFrom+5; iFrom != v.cend(); iFrom = iTo, iTo += 5) cout << *max_element(iFrom, iTo) << '\n'; } 

avec vector iterator + offset out of range échec d’assertion vector iterator + offset out of range . Cela échoue parce que iTo > v.cend() , qui est inoffensif ici. Quel est l’intérêt du débogueur de tester la valeur de l’iterator, qui n’est pas déréférencé?

Au fait, je sais que je peux réécrire la boucle ci-dessus en tant que:

 for (auto i = v.cbegin(); i != v.cend(); i += 5) cout << *max_element(i, i+5) << '\n'; 

mais j’essayais de créer un exemple simple à partir d’un code plus complexe de la vie réelle, dans lequel le calcul de la nouvelle valeur d’iterator est coûteux en calcul.

Je me rends également compte que l’on peut modifier la valeur _ITERATOR_DEBUG_LEVEL afin d’affecter ce comportement, mais cela crée des problèmes avec les versions binarys de certaines bibliothèques, construites avec les parameters de débogage par défaut.

Ce n’est pas anodin … C’est un comportement indéfini de tenter de déplacer l’iterator au-delà de end() , ce que vous faites lors de votre troisième et dernière itération. Le fait que, immédiatement après cela, avec iTo += 5 vous iTo += 5 votre boucle par iFrom != v.cend() sans déréférencer l’iterator, n’est pas pertinent.

Si l’efficacité est vraiment nécessaire et que vous êtes prêt, vous pouvez parier que le nombre d’éléments est un multiple de 5:

 for (auto iFrom = v.cbegin(), iTo = iFrom; iFrom != v.cend(); iFrom = iTo) { iTo += 5; cout << *max_element(iFrom, iTo) << '\n'; } 

Pas tout à fait sûr de ce que la question est ici, mais le “point” est que VS essaie d’aider à éliminer le code dangereux. Oui, en principe, un pointeur pourrait pointer n’importe où si vous ne le déréférenciez pas, mais les iterators sont une abstraction de niveau supérieur et ont la capacité de détecter si une déréférencement serait valide et ainsi générer des erreurs d’exécution. VS l’a fait avec le vector::iterator au moins depuis VS 2007.

max_element () prend deux iterators et parcourt toute la plage entre eux. Si vous y réfléchissez, la plage n’est pas vraiment valide si l’un des iterators est invalide. SGI et Microsoft mentionnent cela comme condition préalable dans leur documentation respective:

SGI:

Les conditions

  • [premier, dernier) est une plage valide.

MSDN:

Remarques

  • La plage référencée doit être valide; tous les pointeurs doivent pouvoir être déréférencés et dans chaque séquence, la dernière position est accessible à partir de la première par incrémentation.

Si j’étais dans votre situation, j’appendais simplement une vérification pour voir si iTo était toujours valide comme première étape de ma boucle. Si ce n’est pas le cas, réglez-le sur la dernière position dans v.