Compatibilidad de los iteradores de depuración
La biblioteca en tiempo de ejecución de Visual C++ detecta un uso incorrecto del iterador, valida y muestra un cuadro de diálogo en tiempo de ejecución. Para habilitar la compatibilidad con el iterador de depuración, debe usar versiones de depuración de la biblioteca estándar de C++ y la biblioteca en tiempo de ejecución de C para compilar el programa. Para obtener más información, vea Características de la biblioteca CRT. Para obtener información sobre cómo usar iteradores comprobados, vea Iteradores comprobados.
El estándar de C++ describe cómo las funciones miembro pueden provocar que los iteradores de un contenedor se conviertan en no válidos. Dos ejemplos son:
Borrar un elemento de un contenedor hace que los iteradores del elemento sean no válidos.
Aumentar el tamaño de un vector mediante inserción causa que los iteradores de
vector
no sean válidos.
Iteradores no válidos
Si compila este programa de ejemplo en modo de depuración, en tiempo de ejecución se valida y finaliza.
// 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 de _ITERATOR_DEBUG_LEVEL
Puede usar la macro de preprocesador _ITERATOR_DEBUG_LEVEL para desactivar la característica de depuración de iteradores en una compilación de depuración. Este programa no valida, pero aún desencadena un comportamiento indefinido.
// 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
Iteradores sin inicializar
También se produce una aserción si intenta usar un iterador antes de que se inicialice, tal como se muestra aquí:
// iterator_debugging_2.cpp
// compile by using: /EHsc /MDd
#include <string>
using namespace std;
int main() {
string::iterator i1, i2;
if (i1 == i2)
;
}
Iteradores incompatibles
En el ejemplo de código siguiente se produce una aserción porque los dos iteradores del algoritmo for_each son incompatibles. Comprobación de algoritmos para determinar si los iteradores que se les suministran hacen referencia al mismo contenedor.
// 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; } );
}
Tenga en cuenta que este ejemplo usa la expresión lambda [] (int& elem) { elem *= 2; }
en lugar de un functor. Aunque esta opción no tiene ningún efecto en el fallo de aserción (un functor parecido provocaría el mismo error) las lambdas son una manera de escribir un bloque corto de código. Para más información sobre las expresiones lambda, consulte Expresiones lambda.
Iteradores que salen del ámbito
Las comprobaciones de iteradores de depuración también provocan que una variable de iterador que se declara en un bucle for
esté fuera de ámbito cuando el ámbito de bucle for
finaliza.
// 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
}
Destructores para iteradores de depuración
Los iteradores de depuración tienen destructores no triviales. Si un destructor no se ejecuta, pero se libera la memoria del objeto, pueden producirse infracciones de acceso y daños en los datos. Considere este ejemplo:
// 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
}