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ż taki 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
}