Debug Mode Implementations

The debug facilities are available for the standard containers as well as the EWL extension containers:

Each container has methods that will invalidate some or all outstanding iterators. If those iterators are invalidated, then their use (except for assigning a new valid iterator) will generate an error. An iterator is considered invalidated if it no longer points into the container, or if the container's method silently causes the iterator to point to a new element within the container. Some methods (such as swap, or list::splice) will transfer ownership of outstanding iterators from one container to another, but otherwise leave them valid.

In this Example of dereference at end: the iterator i is incremented to the end of the vector and then dereferenced and assigned through. In release mode this is undefined behavior and may overwrite other important information in your application. However in debug mode this example prints out:

EWL DEBUG: dereferenced invalid iterator

Listing: Example of dereference at end:
#include <iostream>
#include <vector>
#include <stdexcept>

int main()
{
   try
   {
      std::vector<int> v(10);
      std::vector<int>::iterator i = v.begin() + 9;

      *i = 9;  // ok
      ++i;     // ok
      *i = 10; // error
   } catch (std::exception& e)
      {
         std::cerr << e.what() << '\n';
      }

      catch (...)
      {
         std::cerr << "Unknown exception caught\n";
      }
}

In the Example of iterator/list mismatch: an iterator is initialized to point into the first list. But then this iterator is mistakenly used to erase an element from a second list. This is normally undefined behavior. In debug mode this example prints out:

EWL DEBUG: invalid iterator given to list

Listing: Example of iterator/list mismatch:
#include <iostream>
#include <list>
#include <stdexcept>

int main()
{
   try
   {
      std::list<int> l1(10), l2(10);
      std::list<int>::iterator i = l1.begin();
      l2.erase(i);  // error
   }

   catch (std::exception& e)
   {
     std::cerr << e.what() << '\n';
   }

   catch (...)
   {
      std::cerr << "Unknown exception caught\n";
   }
}

In the Example of use of invalidated iterator: the push_back method on deque invalidates all iterators. When the loop goes to increment i, it is operating on an invalidated iterator. This is normally undefined behavior. In debug mode this example prints out:

EWL DEBUG: increment end or invalid iterator

Listing: Example of use of invalidated iterator:
#include <iostream>
#include <deque>
#include <stdexcept>

int main()
{
   try
   {
      std::deque<int> d(10);
      std::deque<int>::iterator i = d.begin(), e = d.end();
      for (; i != e; ++i)
         d.push_back(0);
   }

   catch (std::exception& e)
   {
     std::cerr << e.what() << '\n';
   }

   catch (...)
   {
      std::cerr << "Unknown exception caught\n";
   }
}