8.3.5. ipalnumber.cpp With string Iterators

A photograph of a wicker basket full of mushrooms.
A C++ container analogized as a basket. (A basket of edible fungi photographed by George Chernilevsky and downloaded from Wikimedia 9/12/2019).

It's often convenient to package data together so we can move it around a program en masse, and access it in useful ways. Computer scientists have designed many different data structures to fill these needs. Collectively, these structures are called container classes in C++ and collections in Java. A basket is a familiar analogy for a data structure: At some point, there may be too many items for us to hold in our hands, but if we put them in a basket, we can hold many items by holding the basket's handle. Most data structures also organize the stored data and allow programmers to access it in specific ways. Linear data structures (e.g., an ArrayList, a vector, or a string) organize their contents serially in a line, which makes sequential or linear access relatively easy.

Programmers use iterators to access the data or elements stored in containers and collections. Each iterator object is tightly bound to a data object (an instance of a container or collection) and returns the data object's elements one at a time. In the case of string objects, iterators return the elements or characters in sequential order, beginning with either the first or last character. As an introductory example to iterators, the ipalnumber example solves the palindrome-number problem using string iterators.

Iterator Operators And Functions

The string class has eight member functions that create different kinds of iterators. The iterators work in pairs to provide a unique combination of three distinct features:

  1. Starting at either the first or the last character in the string
  2. Moving forward (left to right) or backward (right to left) when the "next" character is accessed
  3. Allow or prevent changing the character accessed through the iterator

The iterators appropriately override or reuse some C++ operators for getting the characters from a string in sequential order. The following table summarizes a few member functions and operators needed to solve the palindrome-number problem with iterators.

string Member Functions
begin

Returns an iterator that points to the first character in the string. The iterator naturally moves or iterates from the first character of the string to the last, that is, from left to right.

for (string::iterator i = s.begin(); i != s.end; i++)
end Returns an iterator that points to the last character in the string (it actually points to one character beyond the last character - to what would be the null-termination character in a C-string - which makes looping through the string in the forward direction easy but complicates looping in the reverse direction).
rbegin Returns an iterator that points to the last character in the string - the beginning of the string going in the reverse direction. The natural looping or iteration order is from the end of the string to the beginning or right to left.
for (string::reverse_iterator r = s.rbegin(); r != s.rend(); r++)
rend Returns an iterator that points to the first character in the string (it actually points to the location one character before the beginning of the string), which makes looping through the string in the reverse direction easy but complicates looping in the forward direction.
Iterator Operators
* The dereference operator - returns the character at the current iteration location.
++ The auto-increment operator (both pre and post versions). Advances the iterator to the next character, where the meaning of "next" depends on the kind of iterator.
-- The auto-decrement operator (both pre and post versions). Reverses the iterator to the previous character, where the meaning of "previous" depends on the kind of iterator.
Iterator functions and operators. See Iterators: for a complete list of string iterator functions.

Iterator Reverse Function, Version 1

The main and to_string functions remain unchanged from the previous string solution. The following iterator solutions only affect the reverse function.

string reverse(string s)
{
	string r;					// (a)

	string::reverse_iterator i = s.rbegin();	// (b)
	while(i != s.rend())				// (c)
		r += *i++;				// (d)

	return r;					// (e)
}
A string object represented as a sequence of squares. The <kbd>rbegin()</kbd> function returns an iterator that points to the last character in the string. The <kbd>rend()</kbd> function returns an iterator that points to one character before the first character in the string. Having an iterator point to a character before and outside the string makes it easier to use a for-loop process the characters in the string.
// alternate version: replaces (b), (c), and (d)

for (string::reverse_iterator i = s.rbegin(); i != s.rend(); i++)	// (f)
	r += *i;							// (g)
Iterator-based string reverse function using reverse iterators. The first version of the iterator-based reverse function uses reverse iterators, which move in the reverse (backward or right-to-left) direction when advanced or incremented.
  1. Create an empty string object to hold the reversed string
  2. Get an iterator that points to the end of the string (the beginning when moving in the reverse or right-to-left direction)
  3. Loop while the iterator is not pointing to the first (or last when going in the reverse direction) character in the string
  4. Recall from the C++ operator summary table that the auto increment operator, ++ has a higher precedence than does the indirection operator, *. But also recall that the post version of auto-increment (where the "++" follows the expression) means to "Use the current value and then increment" (see Figure 1). So, the result of the expression *i++ is to dereference the iterator to get the character to which the iterator currently points and then increment or advance the iterator (which, since it is a reverse iterator, moves it to the left). Finally, the += operator concatenates the character to the reversed string r
  5. Return the reversed string
  6. The for-loop demonstrates why all the "end" iterators refer to a location just outside the string: i != s.rend() is true while the iterator, i, is accessing the last character but becomes false after the iterator's last increment
  7. The dereference operator, *, returns the current string character referenced by the iterator, and the concatenation-with-assignment operator, +=, appends the character to the right side of the string r

Iterator Reverse Function, Version 2

string reverse(string s)
{
	string r;				// (a)

	string::iterator i = s.end();		// (b)
	while(i != s.begin())			// (c)
		r += *--i;			// (d)

	return r;				// (e)
}
A string object represented as a sequence of squares. The <kbd>begin()</kbd> function returns an iterator pointing to the first character in the string. The end() function returns an iterator that points to one character beyond the last character in the string. Having an iterator point to a character after and outside the string makes it easier to use a for-loop process the characters in the string.
Iterator-based string reverse function using forward iterators. The second version of the iterator-based reverse function uses forward iterators, which move in the forward (left to right) direction when incremented, but which move in the reverse or backward (right to left) direction when decremented.
  1. Create an empty string object to hold the reversed string
  2. Get an iterator that points to one place beyond the end of the string
  3. Loop while the iterator is not pointing to the first character in the string
  4. The auto decrement operation takes place first (when the "--" comes before the expression, it means, "Decrement and then use the value," see Figure 1). So, *--i backs up one position and then gets the character at the new position by dereferencing the iterator with the dereference operator, *. Then the += operator concatenates the character to the reversed string r
  5. Return the reversed string

Downloadable Code