Suporte ao iterador de depuração

A biblioteca em tempo de execução Visual C++ detecta o uso incorreto do iterador e declara e exibe uma caixa de diálogo em tempo de execução. Para habilitar o suporte do iterador de depuração, é necessário usar versões de depuração da Biblioteca Padrão C++ e da Biblioteca em Runtime C para compilar seu programa. Para obter mais informações, consulte Recursos da biblioteca CRT. Para obter informações sobre como usar iteradores verificados, consulte Iteradores verificados.

O padrão C++ descreve como funções de membro podem fazer com que iteradores em um contêiner se tornem inválidos. Dois exemplos são:

  • Apagar um elemento de um contêiner faz com que os iteradores no elemento se tornem inválidos.

  • Aumentar o tamanho de um vector por meio de envio por push ou inserção faz com que os iteradores no vector se tornem inválidos.

Iteradores inválidos

Se você compilar esse programa de amostra no modo de depuração, ele será declarado e encerrado em tempo de execução.

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

Usar _ITERATOR_DEBUG_LEVEL

É possível usar a macro do pré-processador _ITERATOR_DEBUG_LEVEL para desligar o recurso do iterador de depuração em um build de depuração. Esse programa não declara, mas ainda dispara um comportamento 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 não inicializados

Uma declaração também ocorrerá se você tentar usar um iterador antes de ele ser inicializado, conforme mostrado aqui:

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

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

Iteradores incompatíveis

O exemplo de código a seguir causa uma declaração, pois os dois iteradores do algoritmo for_each são incompatíveis. Os algoritmos verificam para determinar se os iteradores fornecidos para eles referenciam o mesmo contêiner.

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

Observe que esse exemplo usa a expressão lambda [] (int& elem) { elem *= 2; } em vez de um functor. Embora essa escolha não tenha efeito sobre a falha de declaração (um functor semelhante causaria a mesma falha), lambdas são uma forma de escrever um pequeno bloco de código. Para saber mais sobre expressões lambda, confira o artigo sobre expressões lambda.

Iteradores que saem do escopo

Verificações do iterador de depuração também fazem com que uma variável do iterador declarada em um loop for fique fora do escopo ao término do escopo do loop 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
}

Destruidores para iteradores de depuração

Iteradores de depuração têm destruidores não triviais. Se um destruidor não for executado, mas a memória do objeto for liberada, poderão ocorrer violações de acesso e dados corrompidos. Considere este exemplo:

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

Confira também

Visão geral da biblioteca padrão C++