8.3.5. ipalnumber.cpp With string Iterators

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

Programs often operate on large datasets. In such cases, it's convenient to package the discrete data items together so the program can move them around en masse, as a single entity. Computer scientists have designed numerous data structures, called container classes in C+⁠+ and collections in Java, for this purpose. A basket is a familiar metaphor 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 data they store and allow programs 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. Each iterator object is tightly bound to a container object, allowing the program to access the elements one at a time while the iterator "remembers" the current access locations. 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 Functions And Operators

The string class has eight member functions that create different kinds of iterators. Four of the functions (illustrated in the following figure) allow programs to change the string characters through the iterators, while four "constant" functions disallow change. In addition to the member functions, iterators overload or reuse several operators for navigation and character access.

string Member Functions
begin()

Returns an iterator that points to the first character in the string. When incremented, the iterator advances forward (in the English reading direction) one character to the right - accessing the string characters left to right.

for (string::iterator i = s.begin(); i != s.end(); i++)
end() A string object represented as a sequence of squares. The 'begin' function returns an iterator pointing to the first character in the string, and the 'end' function returns an iterator that points to a sentinel to one character beyond the last string character. Returns an iterator that points to a sentinel (red) one character beyond the last character. Having an iterator point to a sentinel after and outside the string makes it easy to use loops to process the string characters.
rbegin() Returns an iterator that points to the last character in the string. When incremented, the iterator "advances" or moves from the last string character toward the first (in the reverse English reading direction), accessing the characters from right to left.
for (string::reverse_iterator r = s.rbegin(); r != s.rend(); r++)
rend() A string object represented as a sequence of squares. The 'rbegin' function returns an iterator pointing to the last character in the string, and the 'rend' function returns an iterator that points to a sentinel to one character before the first string character. Returns an iterator that points to a sentinel (red) one character before the beginning of the string. Having the iterator point to a sentinel before and outside the string makes it easy to use loops to process its characters in the reverse order.
Iterator Operators
* The dereference operator returns the character at the current iteration location.
= The assignment operator assigns an iterator object to an iterator variable.
== and != Tests two iterator objects for equality or inequality.
++ The pre- and post-auto-increment operators. Advances the iterator to the next character: to the right for forward iterators, and to the left for reverse iterators.
-- The pre- and post-auto-decrement operators. Reverses the iterator to the previous character: to the left for forward iterators, and to the right for reverse iterators.
Iterator functions and operators. Programs use pairs of iterator functions to navigate strings in the forward direction (English reading direction or left to right), or the reverse direction (reverse-English reading direction or right to left). Iterators rely on several overloaded operators for navigation and character access. The overloading mechanism is the subject of a later chapter, and it's sufficient for the current discussion to recognize how the operators behave. See Iterators: for a complete list of string iterator functions.

The Palindrome reverse Function With Iterators

The previous section solved the palindrome-number problem by reversing the candidate string. As the string class doesn't provide a reverse function, the example created one. The following figures rewrite the reverse function to demonstrate forward and reverse iterators.

string reverse(string s)
{
	string r;

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

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

	return r;								// (e)
}
A string object represented as a sequence of squares. The 'rbegin()' function returns an iterator pointing to the last character of the string. The 'rend()' function returns an iterator that points to one character before the first character in the string.
Reversing a string with a reverse iterator. The function defines a local string variable, r, to accumulate characters as the iterator extracts them from the parameter string, s.
  1. rbegin() returns a reverse iterator bound to s and pointing to the last character.
  2. rend() returns a sentinel marking the beginning of the string. The statement loops while the iterator is not the sentinel.
  3. The loop iterates through the characters, from the last to the first, ending when i reaches the sentinel. Although the auto increment operator, ++, has a higher precedence than the indirection operator, *, the post-increment operator "uses the current value and then increments." Therefore, the expression dereferences the iterator, getting the current character, then advances the iterator.
  4. An alternate for-loop implementation.
  5. Returns the reversed string.

 

string reverse(string s)
{
	string r;

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

	//for (char c : s)			// (d)
	//	r = c + r;

	return r;				// (e)
}
A string object represented as a sequence of squares. The 'begin()' 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.
Reversing a string with a forward iterator. The second version also defines a local string variable, r, to accumulate characters as the iterator extracts them from the parameter string, s. Although this version uses a forward iterator, it nevertheless iterates from the end of the string to the beginning (i.e., right-to-left) by using the auto-decrement operator.
  1. end() returns a forward iterator bound to s and pointing to the sentinel character marking the end of the string. Starting the iterator at the sentinel requires the program to decrement the iterator before dereferencing it.
  2. begin() returns an iterator pointing to the first character in the string. The statement loops while the iterator is not the sentinel.
  3. For-range loops were made for iterators. They automatically create a forward iterator bound to a linear container and loop through all its elements. This example concatenates the characters on the left-hand side of the reversed string.
  4. An alternate for-loop implementation.
  5. Returns the reversed string.

Downloadable Palindrome Solutions With Iterators

ViewDownloadComments
ipalnumber.cpp ipalnumber.cpp Demonstrates four ways of using iterators to reverse a string