Supporto degli iteratori di debug
La libreria di runtime di Visual C++ rileva l'uso non corretto dell'iteratore, esegue un'asserzione e visualizza una finestra di dialogo in fase di esecuzione. Per abilitare il supporto degli iteratori di debug, è necessario usare le versioni di debug della libreria standard C++ e della libreria di runtime C per compilare il programma. Per altre informazioni, vedere Funzionalità libreria CRT. Per informazioni sull'uso degli iteratori verificati, vedere Iteratori verificati.
Lo standard C++ descrive in che modo le funzioni membro possono far diventare non validi gli iteratori per un contenitore. Di seguito sono riportati due esempi:
La cancellazione di un elemento da un contenitore fa sì che gli iteratori per l'elemento non siano più validi.
L'aumento delle dimensioni di un vettore eseguendo il push o l'inserimento fa sì che gli iteratori nel
vector
non siano più validi.
Iteratori non validi
Se si compila il programma di esempio in modalità di debug, in fase di esecuzione esegue un'asserzione e viene terminato.
// 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
}
Uso di _ITERATOR_DEBUG_LEVEL
È possibile usare la macro del preprocessore _ITERATOR_DEBUG_LEVEL per disattivare la funzionalità di debug dell'iteratore in una build di debug. Questo programma non asserisce, ma attiva comunque un comportamento non definito.
// 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
Iteratori non inizializzati
Un'asserzione si verifica anche se si tenta di usare un iteratore prima dell'inizializzazione, come illustrato di seguito:
// iterator_debugging_2.cpp
// compile by using: /EHsc /MDd
#include <string>
using namespace std;
int main() {
string::iterator i1, i2;
if (i1 == i2)
;
}
Iteratori incompatibili
L'esempio di codice seguente genera un'asserzione poiché i due iteratori per l'algoritmo for_each sono incompatibili. Gli algoritmi tentano di verificare se gli iteratori specificati fanno riferimento allo stesso contenitore.
// 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; } );
}
Si noti che in questo esempio si usa l'espressione lambda [] (int& elem) { elem *= 2; }
anziché un funtore. Anche se questa scelta non ha alcun effetto sull'errore di asserzione, un funtore simile provocherebbe lo stesso errore, le espressioni lambda sono un modo per scrivere un breve blocco di codice. Per altre informazioni sulle espressioni lambda, vedere Espressioni lambda.
Iteratori che escono dall'ambito
I controlli degli iteratori di debug causano anche l'esclusione dall'ambito di una variabile di iteratore dichiarata in un ciclo for
al termine dell'ambito del ciclo for
.
// 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
}
Distruttori per gli iteratori di debug
Gli iteratori di debug hanno distruttori non semplici. Se un distruttore non viene eseguito ma la memoria dell'oggetto viene liberata, potrebbero verificarsi violazioni di accesso e danneggiamento dei dati. Si consideri questo esempio:
// 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
}