C/C++ Tip


C/C++ Tip #11: Overwrite Iterator

Ray Virzi


If you want to copy a sequence into a container, you might use the std::copy algorithm like this:

std::copy(start, end, std::back_inserter(container));

Here start and end are iterators pointing to an input sequence of size N, and container is a container with the push_back function defined in its interface. Assuming that the container starts empty, it will end up containing a copy of each of the N elements in the same order as the original sequence. The back_inserter template function provided by the standard library is very handy because it returns a back_insert_iterator for the container, which is defined in a clever way so that it appends the copied elements to the back of the container.

Now suppose the container is not empty to begin with (e.g., when the container must be reused several times in an iteration loop). You may have to call the clear function on the container first and then insert the new sequence. This will cause all the old objects to be destroyed and each newly inserted object to be constructed. Not only that, but any dynamic storage used by the container itself will also have to be destroyed and recreated, such as the nodes of a list, map, or set. Some implementations of vector may even de-allocate the entire array block when clear is called. It is often much more efficient to copy over the existing elements in place. At first, you might try this:

std::copy(start, end, container.begin());

Here you have a copy-over operation starting at the beginning of the container. But this code will cause a crash if the size of the container is less than the length N of the input sequence. What is needed is a new iterator type that combines both of these methods. The new iterator must perform a copy-over operation until it reaches the end of the container and from then on simply append the items to the end. I call this an overwrite iterator (see Listing 1). Following the Standard’s convention, I provide two helper template functions (see Listing 2) that will generate an overwrite iterator for a given container.

Using the helper functions, you can write:

std::copy(start, end, overwriter(container));

Or if you want to start the copy at another location in the container that begins at some iterator location, you can write:

std::copy(start, end, overwriter(container, it));

The copy algorithm returns an overwrite iterator that points to the next container item following the copied sequence. Since this iterator contains an implicit conversion to the container’s original iterator type, it can easily be used to erase the remaining items in the container (if needed) or to copy another sequence into the container starting where you left off. This solution is now efficient, flexible, safe, and best of all, easy to use.

Ray Virzi has been programming in C and C++ for about eight years and is currently writing software for helicopter maintenance equipment at Chadwick-Helmuth Company in El Monte, California, which was recently acquired by Honeywell Corp. He can be reached for comment via email at mail@rvirzi.com.