Obsługa iteratora debugowania

Biblioteka uruchomieniowa języka Visual C++ wykrywa niepoprawne użycie iteratora oraz potwierdza i wyświetla okno dialogowe w czasie wykonywania. Aby włączyć obsługę iteratora debugowania, należy użyć wersji debugowania standardowej biblioteki C++ i biblioteki środowiska uruchomieniowego języka C, aby skompilować program. Aby uzyskać więcej informacji, zobacz Funkcje biblioteki CRT. Aby uzyskać informacje na temat używania sprawdzanych iteratorów, zobacz Sprawdzone iteratory.

W standardzie C++ opisano, jak funkcje składowe mogą spowodować, że iteratory kontenera staną się nieprawidłowe. Dwa przykłady to:

  • Wymazywanie elementu z kontenera powoduje, że iteratory elementu stają się nieprawidłowe.

  • Zwiększenie rozmiaru wektora przy użyciu wypychania lub wstawiania powoduje, że iteratory stają vector się nieprawidłowe.

Nieprawidłowe iteratory

Jeśli skompilujesz ten przykładowy program w trybie debugowania, w czasie wykonywania zostanie on asercjowany i zakończony.

// 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
}

Korzystanie z _ITERATOR_DEBUG_LEVEL

Możesz użyć makra preprocesora _ITERATOR_DEBUG_LEVEL , aby wyłączyć funkcję debugowania iteratora w kompilacji debugowania. Ten program nie potwierdza, ale nadal wyzwala niezdefiniowane zachowanie.

// 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

Niezainicjowane iteratory

Asercja występuje również w przypadku próby użycia iteratora przed jego zainicjowaniem, jak pokazano poniżej:

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

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

Niezgodne iteratory

Poniższy przykład kodu powoduje aseracje, ponieważ dwa iteratory algorytmu for_each są niezgodne. Algorytmy sprawdzają, czy iteratory dostarczone do nich odwołują się do tego samego kontenera.

// 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; } );
}

Zwróć uwagę, że w tym przykładzie użyto wyrażenia [] (int& elem) { elem *= 2; } lambda zamiast functora. Mimo że ten wybór nie ma wpływu na awarię asercyjności — podobny functor spowodowałby tę samą awarię — wyrażenia lambda są sposobem na napisanie krótkiego bloku kodu. Aby uzyskać więcej informacji na temat wyrażeń lambda, zobacz Wyrażenia lambda.

Iteratory wychodzące z zakresu

Testy iteracyjne debugowania powodują również, że zmienna iteratora zadeklarowana w for pętli jest poza zakresem po zakończeniu for zakresu pętli.

// 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
}

Destruktory dla iteratorów debugowania

Iteratory debugowania mają nietrywialne destruktory. Jeśli destruktor nie zostanie uruchomiony, ale pamięć obiektu zostanie zwolniona, mogą wystąpić naruszenia dostępu i uszkodzenie danych. Rozważmy następujący przykład:

// 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
}

Zobacz też

Standardowa biblioteka C++ — przegląd