Was this page helpful?
Your feedback about this content is important. Let us know what you think.
Additional feedback?
1500 characters remaining
Debug Iterator Support
Collapse the table of content
Expand the table of content

Debug Iterator Support

The Visual C++ runtime library now detects incorrect iterator use and will assert and display a dialog box at run time. To enable debug iterator support, a program must be compiled with a debug version of a C run time library (see C Run-Time Libraries for more information).

See Checked Iterators for more information on using iterators.

The C++ standard describes which member functions cause iterators to a container to become invalid. Two examples are:

  • Erasing an element from a container causes iterators to the element to become invalid.

  • Increasing the size of a vector (push or insert) causes iterators into the vector container become invalid.

Compile the following program in debug mode and at runtime it will assert and terminate.

/* compile with /D_DEBUG /EHsc /MDd */
#include <vector>
#include <iostream>

int main() {
   std::vector<int> v ;
   
   v.push_back(10);
   v.push_back(15);
   v.push_back(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
}

The symbol _HAS_ITERATOR_DEBUGGING can be used to turn off the iterator debugging feature in a debug build. The following program will not assert:

// iterator_debugging.cpp
// compile with: /D_DEBUG /EHsc /MDd
#define _HAS_ITERATOR_DEBUGGING 0
#include <vector>
#include <iostream>

int main() {
   std::vector<int> v ;
   
   v.push_back(10);
   v.push_back(15);
   v.push_back(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

An assert will also occur if you attempt to use an iterator before it is initialized:

/* compile with /EHsc /MDd */
#include <string>
using namespace std;
int main() {
   string::iterator i1, i2;
   if (i1 == i2)
      ;
}

The following code example will cause an assertion because the two iterators to the for_each algorithm are incompatible. All algorithms check to see that the iterators supplied to them are referencing the same container.

/* compile with /D_DEBUG /EHsc /MDd */
#include <algorithm>
#include <vector>
using namespace std;

// The function object multiplies an element by a Factor
template <class Type>
class MultValue
{
private:
    Type Factor;   // The value to multiply by
public:
    // Constructor initializes the value to multiply by
    MultValue(const Type& val ) : Factor(val) { }

    // The function call for the element to be multiplied
    void operator()(Type& elem) const
    {
        elem *= Factor;
    }
};

int main()
{
    vector<int> v1;
    vector<int> v2;

    v1.push_back(10);
    v1.push_back(20);

    v2.push_back(10);
    v2.push_back(20);

    // This next line will assert because v1 and v2 are
    // incompatible.
    for_each(v1.begin(), v2.end(), MultValue<int>(-2));
}

Debug iterator checking also implies /Zc:forScope, such that, an iterator variable declared in a for loop will not be in scope when the for loop scope ends.

// debug_iterator.cpp
// compile with: /EHsc /MDd
#include <vector>
#include <iostream>
int main() {
   std::vector<int> v ;
   
   v.push_back(10);
   v.push_back(15);
   v.push_back(20);
   
   for (std::vector<int>::iterator i = v.begin() ; i != v.end(); ++i)
   ;
   --i;   // C2065
}

Debug iterators have non-trivial destructors. If a destructor does not run, for whatever reason, it could lead to access violations and data corruption. Consider the following example:

/* compile with: /D_DEBUG /EHsc /MDd */
#include <vector>
struct base {
   // 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
}

Community Additions

ADD
Show:
© 2015 Microsoft