C++标准模板库 迭代器 iterator 详解(一)

时间:2022-04-21 21:39:59

#include <vector>
#include <iostream>
#include <list>
#include <algorithm>
#include <iterator> //copy
using namespace std;

template <class T>
inline void print (const T& coll, const char* optcstr="")
{
typename T::const_iterator pos;

std::cout << optcstr;
for (pos=coll.begin(); pos!=coll.end(); ++pos)
{
std::cout << *pos << ' ';
}
std::cout << std::endl;
}

void test_random_access_iterator()
{
vector<int> coll;
// insert elements from 1991 to 2013
for (int i=1991; i<=2013; ++i)
{
coll.push_back (i);
}

/* print number of elements by processing the distance between beginning and end
* - NOTE: uses operator - for iterators
*/
cout << "number/distance: " << coll.end()-coll.begin() << endl;

/* print all elements
* - NOTE: uses operator < instead of operator !=
*/
vector<int>::iterator pos;
for (pos=coll.begin(); pos<coll.end(); ++pos)
{
cout << *pos << ' ';
}
cout << endl;

/* print all elements
* - NOTE: uses operator [] instead of operator *
*/
for (int i=0; i<coll.size(); ++i)
{
//cout << coll.begin()[i] << ' '; 和如下语句效果相同
cout << coll[i] << ' ';
}
cout << endl;

/* print every second element
* - NOTE: uses operator +=
*/
for (pos = coll.begin(); pos < coll.end()-1; pos += 2)
{
cout << *pos << ' ';
}
cout << endl;
}
/********************************************
运行结果:
number/distance: 23
1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006
2007 2008 2009 2010 2011 2012 2013
1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006
2007 2008 2009 2010 2011 2012 2013
1991 1993 1995 1997 1999 2001 2003 2005 2007 2009 2011
*********************************************/
void test_advance()
{
list<int> coll;
// insert elements from 1 to 9
for (int i=2007; i<=2014; ++i)
{
coll.push_back(i);
}
//打印整个链表
print(coll,"print the list as follow:\n");
list<int>::iterator pos = coll.begin();
// print actual element
cout<<endl;
cout << *pos << endl;
// step three elements forward
cout<<endl<<"after advance (pos, 3)\n";
advance (pos, 3);
// print actual element
cout << *pos << endl;
// step one element backward
cout<<endl<<"after advance (pos, -1)\n";

advance (pos, -1);
// print actual element
cout << *pos << endl;
}
/********************************************
运行结果:
print the list as follow:
2007 2008 2009 2010 2011 2012 2013 2014

2007

after advance (pos, 3)
2010

after advance (pos, -1)
2009
*********************************************/
void test_distance()
{
list<int> coll;

// insert elements from -3 to 9
for (int i=2007; i<=2014; ++i)
{
coll.push_back(i);
}
print(coll,"print the list as follow:\n");

// search element with value 2010
list<int>::iterator pos;
pos = find (coll.begin(), coll.end(), // range
2010); // value

if (pos != coll.end())
{
// process and print difference from the beginning
cout << "difference between beginning and 2010: "
<< distance(coll.begin(),pos) << endl;
}
else
{
cout << "2010 not found" << endl;
}
}
/********************************************
运行结果:
print the list as follow:
2007 2008 2009 2010 2011 2012 2013 2014
difference between beginning and 2010: 3
*********************************************/
void test_iter_swap()
{
list<int> coll;

// insert elements from 1 to 9
for (int i=2007; i<=2014; ++i)
{
coll.push_back(i);
}

print(coll,"print list as follow:\n");

// swap first and second value
iter_swap (coll.begin(), ++coll.begin());

print(coll,"after iter_swap (coll.begin(), ++coll.begin()) \n");

// swap first and last value
iter_swap (coll.begin(), --coll.end());
print(coll,"after iter_swap (coll.begin(), --coll.end()) \n");
}
/********************************************
运行结果:
print list as follow:
2007 2008 2009 2010 2011 2012 2013 2014
after iter_swap (coll.begin(), ++coll.begin())
2008 2007 2009 2010 2011 2012 2013 2014
after iter_swap (coll.begin(), --coll.end())
2014 2007 2009 2010 2011 2012 2013 2008
*********************************************/
void print_element (int elem)
{
cout << elem << ' ';
}

void test_reverse_iterator()
{
list<int> coll;

// insert elements from 1937 to 1945
for (int i=1937; i<=1945; ++i)
{
coll.push_back(i);
}
cout<<"print all elements in normal order:\n";

for_each (coll.begin(), coll.end(), // range
print_element); // operation
cout << endl;

cout<<"print all elements in reverse order:\n";
for_each (coll.rbegin(), coll.rend(), // range
print_element); // operations
cout << endl;
// find position of element with value 1938
list<int>::iterator pos1;
cout<<"find [1938,1942):\n";
pos1 = find (coll.begin(), coll.end(), // range
1938); // value

cout<<"pos1 is :"<<*pos1<<endl;
list<int>::reverse_iterator rpos1(pos1);
cout<<"rpos1 is :"<<*rpos1<<endl;
cout<<"rpos1.base() is "<<*rpos1.base()<<endl;

// find position of element with value 1942
list<int>::iterator pos2;
pos2 = find (coll.begin(), coll.end(), // range
1942); // value

cout<<"pos2 is :"<<*pos2<<endl;
list<int>::reverse_iterator rpos2(pos2);
cout<<"rpos2 is :"<<*rpos2<<endl;
cout<<"rpos2.base() is "<<*rpos2.base()<<endl;

// print all elements in range [pos1,pos2)
for_each (pos1, pos2, // range
print_element); // operation
cout << endl;

cout<<"reverse [1938,1942):\n";
// print all elements in range [pos1,pos2) in reverse order
for_each (rpos2, rpos1, // range
print_element); // operation
cout << endl;
}
/********************************************
运行结果:
print all elements in normal order:
1937 1938 1939 1940 1941 1942 1943 1944 1945
print all elements in reverse order:
1945 1944 1943 1942 1941 1940 1939 1938 1937
find [1938,1942):
pos1 is :1938
rpos1 is :1937
rpos1.base() is 1938
pos2 is :1942
rpos2 is :1941
rpos2.base() is 1942
1938 1939 1940 1941
reverse [1938,1942):
1941 1940 1939 1938

*********************************************/
int main()
{
return 0;
}









<iterator>

Iterator definitions
An iterator is any object that, pointing to some element in a range of elements (such as an array or a container), has the ability to iterate through the elements of that range using a set of operators (with at least the increment (++) and dereference (*) operators).

The most obvious form of iterator is a pointer: A pointer can point to elements in an array, and can iterate through them using the increment operator (++). But other kinds of iterators are possible. For example, each container type (such as alist) has a specific iterator type designed to iterate through its elements.

Notice that while a pointer is a form of iterator, not all iterators have the same functionality of pointers; Depending on the properties supported by iterators, they are classified into five different categories:

Iterator categories

Iterators are classified into five categories depending on the functionality they implement:



Input and output iterators are the most limited types of iterators: they can perform sequential single-pass input or output operations.


Forward iterators have all the functionality of input iterators and if they are not constant iterators- also the functionality of output iterators, although they are limited to one direction in which to iterate through a range (forward). All standard containers support at least forward iterator types.

Bidirectional iterators are like forward iterators but can also be iterated through backwards.

Random-access iterators implement all the functionality of bidirectional iterators, and also have the ability to access ranges non-sequentially: distant elements can be accessed directly by applying an offset value to an iterator without iterating through all the elements in between. These iterators have a similar functionality to standard pointers (pointers are iterators of this category).

The properties of each iterator category are:

category properties valid expressions
all categories copy-constructible, copy-assignable and destructible X b(a);
b = a;
Can be incremented ++a
a++
Random Access Bidirectional Forward Input Supports equality/inequality comparisons a == b
a != b
Can be dereferenced as an rvalue *a
a->m
Output Can be dereferenced as an lvalue 
(only for mutable iterator types)
*a = t
*a++ = t

default-constructible X a;
X()
Multi-pass: neither dereferencing nor incrementing affects dereferenceability { b=a; *a++; *b; }

Can be decremented --a
a--
*a--

Supports arithmetic operators + and - a + n
n + a
a - n
a - b
Supports inequality comparisons (<, >, <= and >=) between iterators a < b
a > b
a <= b
a >= b
Supports compound assignment operations += and -= a += n
a -= n
Supports offset dereference operator ([]) a[n]

Where X is an iterator type, a and b are objects of this iterator type, t is an object of the type pointed by the iterator type, and n is an integer value.


Functions

Iterator operations:

Iterator generators:

Classes


Predefined iterators



#include <vector>
#include <iostream>
#include <list>
#include <algorithm>
#include <iterator> //copy
using namespace std;

template <class T>
inline void print (const T& coll, const char* optcstr="")
{
typename T::const_iterator pos;

std::cout << optcstr;
for (pos=coll.begin(); pos!=coll.end(); ++pos)
{
std::cout << *pos << ' ';
}
std::cout << std::endl;
}

void test_random_access_iterator()
{
vector<int> coll;
// insert elements from 1991 to 2013
for (int i=1991; i<=2013; ++i)
{
coll.push_back (i);
}

/* print number of elements by processing the distance between beginning and end
* - NOTE: uses operator - for iterators
*/
cout << "number/distance: " << coll.end()-coll.begin() << endl;

/* print all elements
* - NOTE: uses operator < instead of operator !=
*/
vector<int>::iterator pos;
for (pos=coll.begin(); pos<coll.end(); ++pos)
{
cout << *pos << ' ';
}
cout << endl;

/* print all elements
* - NOTE: uses operator [] instead of operator *
*/
for (int i=0; i<coll.size(); ++i)
{
//cout << coll.begin()[i] << ' '; 和如下语句效果相同
cout << coll[i] << ' ';
}
cout << endl;

/* print every second element
* - NOTE: uses operator +=
*/
for (pos = coll.begin(); pos < coll.end()-1; pos += 2)
{
cout << *pos << ' ';
}
cout << endl;
}
/********************************************
运行结果:
number/distance: 23
1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006
2007 2008 2009 2010 2011 2012 2013
1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006
2007 2008 2009 2010 2011 2012 2013
1991 1993 1995 1997 1999 2001 2003 2005 2007 2009 2011
*********************************************/
void test_advance()
{
list<int> coll;
// insert elements from 1 to 9
for (int i=2007; i<=2014; ++i)
{
coll.push_back(i);
}
//打印整个链表
print(coll,"print the list as follow:\n");
list<int>::iterator pos = coll.begin();
// print actual element
cout<<endl;
cout << *pos << endl;
// step three elements forward
cout<<endl<<"after advance (pos, 3)\n";
advance (pos, 3);
// print actual element
cout << *pos << endl;
// step one element backward
cout<<endl<<"after advance (pos, -1)\n";

advance (pos, -1);
// print actual element
cout << *pos << endl;
}
/********************************************
运行结果:
print the list as follow:
2007 2008 2009 2010 2011 2012 2013 2014

2007

after advance (pos, 3)
2010

after advance (pos, -1)
2009
*********************************************/
void test_distance()
{
list<int> coll;

// insert elements from -3 to 9
for (int i=2007; i<=2014; ++i)
{
coll.push_back(i);
}
print(coll,"print the list as follow:\n");

// search element with value 2010
list<int>::iterator pos;
pos = find (coll.begin(), coll.end(), // range
2010); // value

if (pos != coll.end())
{
// process and print difference from the beginning
cout << "difference between beginning and 2010: "
<< distance(coll.begin(),pos) << endl;
}
else
{
cout << "2010 not found" << endl;
}
}
/********************************************
运行结果:
print the list as follow:
2007 2008 2009 2010 2011 2012 2013 2014
difference between beginning and 2010: 3
*********************************************/
void test_iter_swap()
{
list<int> coll;

// insert elements from 1 to 9
for (int i=2007; i<=2014; ++i)
{
coll.push_back(i);
}

print(coll,"print list as follow:\n");

// swap first and second value
iter_swap (coll.begin(), ++coll.begin());

print(coll,"after iter_swap (coll.begin(), ++coll.begin()) \n");

// swap first and last value
iter_swap (coll.begin(), --coll.end());
print(coll,"after iter_swap (coll.begin(), --coll.end()) \n");
}
/********************************************
运行结果:
print list as follow:
2007 2008 2009 2010 2011 2012 2013 2014
after iter_swap (coll.begin(), ++coll.begin())
2008 2007 2009 2010 2011 2012 2013 2014
after iter_swap (coll.begin(), --coll.end())
2014 2007 2009 2010 2011 2012 2013 2008
*********************************************/
void print_element (int elem)
{
cout << elem << ' ';
}

void test_reverse_iterator()
{
list<int> coll;

// insert elements from 1937 to 1945
for (int i=1937; i<=1945; ++i)
{
coll.push_back(i);
}
cout<<"print all elements in normal order:\n";

for_each (coll.begin(), coll.end(), // range
print_element); // operation
cout << endl;

cout<<"print all elements in reverse order:\n";
for_each (coll.rbegin(), coll.rend(), // range
print_element); // operations
cout << endl;
// find position of element with value 1938
list<int>::iterator pos1;
cout<<"find [1938,1942):\n";
pos1 = find (coll.begin(), coll.end(), // range
1938); // value

cout<<"pos1 is :"<<*pos1<<endl;
list<int>::reverse_iterator rpos1(pos1);
cout<<"rpos1 is :"<<*rpos1<<endl;
cout<<"rpos1.base() is "<<*rpos1.base()<<endl;

// find position of element with value 1942
list<int>::iterator pos2;
pos2 = find (coll.begin(), coll.end(), // range
1942); // value

cout<<"pos2 is :"<<*pos2<<endl;
list<int>::reverse_iterator rpos2(pos2);
cout<<"rpos2 is :"<<*rpos2<<endl;
cout<<"rpos2.base() is "<<*rpos2.base()<<endl;

// print all elements in range [pos1,pos2)
for_each (pos1, pos2, // range
print_element); // operation
cout << endl;

cout<<"reverse [1938,1942):\n";
// print all elements in range [pos1,pos2) in reverse order
for_each (rpos2, rpos1, // range
print_element); // operation
cout << endl;
}
/********************************************
运行结果:
print all elements in normal order:
1937 1938 1939 1940 1941 1942 1943 1944 1945
print all elements in reverse order:
1945 1944 1943 1942 1941 1940 1939 1938 1937
find [1938,1942):
pos1 is :1938
rpos1 is :1937
rpos1.base() is 1938
pos2 is :1942
rpos2 is :1941
rpos2.base() is 1942
1938 1939 1940 1941
reverse [1938,1942):
1941 1940 1939 1938

*********************************************/
int main()
{
return 0;
}







std::advance

template <class InputIterator, class Distance>
void advance (InputIterator& it, Distance n);
Advance iterator
Advances the iterator   it  by   n  element positions.

If   it  is a   random-access iterator, the function uses just once   operator+  or   operator-. Otherwise, the function uses repeatedly the increase or decrease operator ( operator++  or   operator--) until   n  elements have been advanced.

Parameters

it
Iterator to be advanced.
InputIterator  shall be at least an   input iterator.
n
Number of element positions to advance.
This shall only be negative for   random-access  and   bidirectional  iterators.
Distance  shall be a numerical type able to represent distances between iterators of this type.

Return value

none


std::distance

template<class InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance (InputIterator first, InputIterator last);
Return distance between iterators
Calculates the number of elements between   first  and   last.

If   it  is a   random-access iterator, the function uses   operator-  to calculate this. Otherwise, the function uses the increase operator ( operator++ ) repeatedly.

Parameters

first
Iterator pointing to the initial element.
last
Iterator pointing to the final element. This must be reachable from   first.
InputIterator  shall be at least an   input iterator.

Return value

The number of elements between   first  and   last.


Summary

The Good
  • The STL provides iterators as a convenient abstraction for accessing many different types of containers.
  • Iterators for templated classes are generated inside the class scope with the syntax
    class_name<parameters>::iterator
  • Iterators can be thought of as limited pointers (or, in the case of random access iterators, as nearly equivalent to pointers)
The Gotchas
  • Iterators do not provide bounds checking; it is possible to overstep the bounds of a container, resulting in segmentation faults
  • Different containers support different iterators, so it is not always possible to change the underlying container type without making changes to your code
  • Iterators can be invalidated if the underlying container (the container being iterated over) is changed significantly