Prise en charge de l’itérateur de débogage

La bibliothèque Runtime Visual C++ détecte l’utilisation d’itérateurs incorrects, et effectue une assertion et affiche une boîte de dialogue au moment de l’exécution. Pour activer la prise en charge des itérateurs de débogage, vous devez utiliser les versions Debug de la bibliothèque C++ Standard et de la bibliothèque Runtime C pour compiler votre programme. Pour plus d’informations, consultez Fonctionnalités de la bibliothèque CRT. Pour plus d’informations sur l’utilisation d’itérateurs vérifiés, consultez Itérateurs vérifiés.

La norme C++ décrit comment les fonctions membres peuvent entraîner la non-validité des itérateurs vers un conteneur. En voici deux exemples:

  • La suppression d’un élément d’un conteneur entraîne la non-validité des itérateurs vers l’élément.

  • L’augmentation de la taille d’un vecteur à l’aide de push ou insert entraîne la non-validité des itérateurs dans le vector.

Itérateurs non valides

Si vous compilez cet exemple de programme en mode débogage, au moment de l’exécution il effectue une assertion et s’arrête.

// iterator_debugging_0.cpp
// compile by using /EHsc /MDd
#include <vector>
#include <iostream>

int main() {
   std::vector<int> v {10, 15, 20};
   std::vector<int>::iterator i = v.begin();
   ++i;

   std::vector<int>::iterator j = v.end();
   --j;

   std::cout << *j << '\n';

   v.insert(i,25);

   std::cout << *j << '\n'; // Using an old iterator after an insert
}

Utilisation de _ITERATOR_DEBUG_LEVEL

Vous pouvez utiliser la macro de préprocesseur _ITERATOR_DEBUG_LEVEL pour désactiver la fonctionnalité de débogage des itérateurs dans une version Debug. Ce programme n’affirme pas, mais déclenche toujours un comportement non défini.

// iterator_debugging_1.cpp
// compile by using: /EHsc /MDd
#define _ITERATOR_DEBUG_LEVEL 0
#include <vector>
#include <iostream>

int main() {
    std::vector<int> v {10, 15, 20};

   std::vector<int>::iterator i = v.begin();
   ++i;

   std::vector<int>::iterator j = v.end();
   --j;

   std::cout << *j << '\n';

   v.insert(i,25);

   std::cout << *j << '\n'; // Using an old iterator after an insert
}
20
-572662307

Itérateurs non initialisés

Une assertion se produit également si vous tentez d’utiliser un itérateur avant son initialisation, comme illustré ici :

// iterator_debugging_2.cpp
// compile by using: /EHsc /MDd
#include <string>
using namespace std;

int main() {
   string::iterator i1, i2;
   if (i1 == i2)
      ;
}

Itérateurs incompatibles

L’exemple de code suivant provoque une assertion, car les deux itérateurs vers l’algorithme for_each ne sont pas compatibles. Les algorithmes vérifient si les itérateurs qui leur sont fournis référencent le même conteneur.

// iterator_debugging_3.cpp
// compile by using /EHsc /MDd
#include <algorithm>
#include <vector>
using namespace std;

int main()
{
    vector<int> v1 {10, 20};
    vector<int> v2 {10, 20};

    // The next line asserts because v1 and v2 are
    // incompatible.
    for_each(v1.begin(), v2.end(), [] (int& elem) { elem *= 2; } );
}

Notez que cet exemple utilise l’expression lambda [] (int& elem) { elem *= 2; } au lieu d’un foncteur. Bien que ce choix n’ait aucune incidence sur l’échec de l’assertion ( un fonctor similaire provoquerait le même échec), les lambdas sont un moyen d’écrire un bloc de code court. Pour plus d’informations sur les expressions lambda, voir Expressions lambda.

Itérateurs sortant de la portée

La vérification des itérateur de débogage provoque également une variable d’itérateur déclarée dans une boucle for comme étant hors de portée quand la portée de la boucle for se termine.

// iterator_debugging_4.cpp
// compile by using: /EHsc /MDd
#include <vector>
#include <iostream>
int main() {
   std::vector<int> v {10, 15, 20};

   for (std::vector<int>::iterator i = v.begin(); i != v.end(); ++i)
      ;   // do nothing
   --i;   // C2065
}

Destructeurs pour les itérateurs de débogage

Les itérateurs de débogage ont des destructeurs non triviaux. Si un destructeur ne s’exécute pas, mais que la mémoire de l’objet est libérée, les violations d’accès et la corruption des données peuvent se produire. Prenons cet exemple :

// iterator_debugging_5.cpp
// compile by using: /EHsc /MDd
#include <vector>
struct base {
   // TO FIX: uncomment the next line
   // virtual ~base() {}
};

struct derived : base {
   std::vector<int>::iterator m_iter;
   derived( std::vector<int>::iterator iter ) : m_iter( iter ) {}
   ~derived() {}
};

int main() {
   std::vector<int> vect( 10 );
   base * pb = new derived( vect.begin() );
   delete pb;  // doesn't call ~derived()
   // access violation
}

Voir aussi

Vue d’ensemble de la bibliothèque standard C++