Iterator Invalidation Problem

Iterator invalidation can occur when using iterators (usually ExternalIterators, though InternalIterators can be affected too) to traverse a mutable container.

The problem occurs when a container that is being processed using an iterator has its shape changed during the process. (We will assume a single-threaded application; concurrent access to a mutable container is a whole 'nother can of worms which we won't get into on this page). By "having its shape change", one of the following types of mutations is meant:

In general, simple mutations that don't change the "shape" of the container (such as replacing the third element of an array with a new value) don't cause problems.

The problem is, of course, that any outstanding iterators which refer to the container may become invalid, or be caused to point to a different element (or even a different container). If performing a traversal, the traversal invariant (each node visited exactly once) may be violated by this. In some cases, there is no way to detect that the iterator has been invalidated, and further use of it results in UndefinedBehavior! (In languages that have UndefinedBehavior, that is. Otherwise probably an exception or some unpredictable traversal order.)

The CeePlusPlus StandardTemplateLibrary, for example, meticulously documents exactly what effects container mutations have on STL iterators; in many cases iterators can become invalidated with UndefinedBehavior the result. (Often, this depends on the underlying state of the container--for example, appending an element to a vector<T> will invalide all existing iterators--turning them all into WildPointers, essentially--if the append causes a resize. Which doesn't always occur; as vector<T> generally doubles its size when it needs more room (DoubleAfterFull); so most such allocations are harmless).

The problem is excacerbated by the fact that for many efficient container implementations, iterators have internal (and somewhat incestuous) knowedge of the containers they point to, and/or are often very low-level abstractions under the hood. Again picking on C++, vector<T>::iterator is usually little more than a T* pointing somewhere into the middle of the array.

Possible solutions to this problem:


EditText of this page (last edited May 21, 2008) or FindPage with title or text search