Поддержка итераторов отладки

Библиотека времени выполнения Visual C++ обнаруживает некорректное использование итераторов, выполняет проверочное утверждение и отображает диалоговое окно во время выполнения. Чтобы включить поддержку отладочных итераторов, необходимо использовать отладочные версии стандартной библиотеки C++ и библиотеки времени выполнения C для компиляции программы. Дополнительные сведения см. в разделе Функции библиотеки CRT. Сведения об использовании проверяемых итераторов см. в разделе Проверяемые итераторы.

В стандарте языка C++ описано, как функции-члены могут сделать недействительными итераторы в контейнер. Ниже приведены два примера:

  • В случае удаления элемента из контейнера итераторы в этот элемент становятся недействительными.

  • Увеличение размера вектора с помощью операции выталкивания или вставки делает недействительными итераторы в vector.

Недопустимые итераторы

При компиляции данного примера программы в режиме отладки во время выполнения она выполняет подтверждение и прекращает выполнение.

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

Использование _ITERATOR_DEBUG_LEVEL

Для выключения функции отладки итераторов в отладочной сборке можно использовать макрос препроцессора _ITERATOR_DEBUG_LEVEL. Эта программа не утверждает, но по-прежнему запускает неопределенное поведение.

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

Неинициализированные итераторы

Утверждение также возникает при попытке использовать итератор перед инициализацией, как показано ниже:

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

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

Несовместимые итераторы

Следующий пример кода вызывает проверочное утверждение, так как два итератора для алгоритма for_each несовместимы. Алгоритмы пытаются проверить, ссылаются ли предоставляемые в них итераторы на один и тот же контейнер.

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

Обратите внимание, что в примере используется лямбда-выражение [] (int& elem) { elem *= 2; }, а не функция. Хотя этот выбор не имеет никакого отношения к сбою утверждения , аналогичный functor приведет к тому же сбою, лямбда-лямбда-код является способом записи короткого блока кода. Дополнительные сведения о лямбда-выражениях см. в разделе Лямбда-выражения.

Итераторы выходят из область

Проверки отладочных итераторов также приводят к выходу за пределы области переменной-итератора, которая объявлена в цикле for, когда область цикла 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
}

Деструкторы для отладочных итераторов

Отладочные итераторы имеют нетривиальные деструкторы. Если деструктор не выполняется, но память объекта освобождается, могут возникнуть нарушения доступа и повреждение данных. Рассмотрим следующий пример.

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

См. также

Общие сведения о стандартной библиотеке C++