迭代器
迭代器iterator 提供了一种一般化的方法对顺序或关联容器类型中的每个元素进行
连续访问例如假设iter 为任意容器类型的一个iterator 则
++iter;
向前移动迭代器使其指向容器的下一个元素而
*iter;
返回iterator 指向元素的值
每种容器类型都提供一个begin()和一个end()成员函数
begin()返回一个iterator 它指向容器的第一个元素
end()返回一个iterator 它指向容器的末元素的下一个位置
为了迭代任意容器类型的元素我们可以这样写
for ( iter = container.begin();
iter != container.end(); ++iter )
do_something_with_element( *iter );
由于模板和嵌套类语法的原因iterator 的定义看起来有点吓人例如下面是一对iterator
的定义它们指向一个内含string 元素的vector
// vector<string> vec;
vector<string>::iterator iter = vec.begin();
vector<string>::iterator iter_end = vec.end();
iterator 是vector 类中定义的typedef 以下语法
vector<string>::iterator
引用了vector 类中内嵌的iterator typedef 并且该vector 类包含string 类型的元素
为了把每个string 元素打印到标准输出上我们可以这样写
for( ; iter != iter_end; ++iter )
cout << *iter << '\n';
当然这里*iter 的运算结果就是实际的string 对象
除了iterator 类型每个容器还定义了一个const iterator 类型后者对于遍历const 容器
是必需的const iterator 允许以只读方式访问容器的底层元素例如
#include <vector >
void even_odd( const vector<int> *pvec,
vector<int> *pvec_even,
vector<int> *pvec_odd )
{
// 必须声明一个const_iterator, 才能够遍历pvec
vector<int>::const_iterator c_iter = pvec->begin();
vector<int>::const_iterator c_iter_end = pvec->end();
for ( ; c_iter != c_iter_end; ++c_iter )
if ( *c_iter % 2 )
pvec_odd->push_back( *c_iter );
else pvec_even->push_back( *c_iter );
}
最后如果我们希望查看这些元素的某个子集该怎么办呢如每隔一个元素或每隔三
个元素或者从中间开始逐个访问元素我们可以用标量算术运算使iterator 从当前位置偏移
到某个位置上例如
vector<int>::iterator iter = vec.begin()+vec.size()/2;
将iter 指向vec 的中间元素而
iter += 2;
将iter 向前移动两个元素
iterator 算术论算只适用于vector 或deque 而不适用于list 因为list 的元素在内存中不
是连续存储的例如
ilist.begin() + 2;
是不正确的因为在list 中向前移动两个元素需要沿着内部next 指针走两次对于vector
或deque 前进两个元素需要把当前的地址值加上两个元素的长度3.3 节给出了关于指针算
术运算的讨论
容器对象也可以用由一对iterator 标记的起始元素和未元素后一位置之间的拷贝来初
始化例如假设我们有
#include <vector>
#include <string>
#include <iostream>
int main()
{
vector<string> svec;
string intext;
while ( cin >> intext )
svec.push_back( intext );
// process svec ...
}
我们可以定义一个新的vector 来拷贝svec 的全部或部分元素
int main()
{
vector<string> svec;
// ...
// 用svec 的全部元素初始化svec2
vector<string> svec2( svec.begin(), svec.end() );
// 用svec 的前半部分初始化svec3
vector<string>::iterator it =
svec.begin() + svec.size()/2;
vector<string> svec3( svec.begin(), it );
// 处理 vectors ...
}
用特定的istream_iterator 类型可以更直接地向svec 插入文
本元素
#include <vector>
#include <string>
#include < iterator >
int main()
{
// 将输入流iterator 绑定到标准输入上
istream_iterator<string> infile( cin );
// 标记流结束位置的输入流iterator
istream_iterator<string> eos;
// 利用通过cin 输入的值初始化svec
vector<string> svec( infile, eos );
// 处理 svec
}
除了一对iterator 之外两个指向内置数组的指针也可以被用作元素范围标记器range
marker 例如假设我们有下列string 对象的数组
#include <string>
string words[4] = {
"stately", "plump", "buck", "mulligan"
};
可以通过传递数组words 的首元素指针和末元素后一位置的指针来初始化string
vector
vector< string > vwords( words, words+4 );
第二个指针被用作终止条件它指向的对象通常指向容器或者数组中最后一个元素后
面的位置上不包含在要被拷贝或遍历的元素之中
类似地我们可以按如下方式初始化一个内含int 型元素的list
int ia[6] = { 0, 1, 2, 3, 4, 5 };
list< int > ilist( ia, ia+6 );
迭代器iterator 提供了一种一般化的方法对顺序或关联容器类型中的每个元素进行
连续访问例如假设iter 为任意容器类型的一个iterator 则
++iter;
向前移动迭代器使其指向容器的下一个元素而
*iter;
返回iterator 指向元素的值
每种容器类型都提供一个begin()和一个end()成员函数
begin()返回一个iterator 它指向容器的第一个元素
end()返回一个iterator 它指向容器的末元素的下一个位置
为了迭代任意容器类型的元素我们可以这样写
for ( iter = container.begin();
iter != container.end(); ++iter )
do_something_with_element( *iter );
由于模板和嵌套类语法的原因iterator 的定义看起来有点吓人例如下面是一对iterator
的定义它们指向一个内含string 元素的vector
// vector<string> vec;
vector<string>::iterator iter = vec.begin();
vector<string>::iterator iter_end = vec.end();
iterator 是vector 类中定义的typedef 以下语法
vector<string>::iterator
引用了vector 类中内嵌的iterator typedef 并且该vector 类包含string 类型的元素
为了把每个string 元素打印到标准输出上我们可以这样写
for( ; iter != iter_end; ++iter )
cout << *iter << '\n';
当然这里*iter 的运算结果就是实际的string 对象
除了iterator 类型每个容器还定义了一个const iterator 类型后者对于遍历const 容器
是必需的const iterator 允许以只读方式访问容器的底层元素例如
#include <vector >
void even_odd( const vector<int> *pvec,
vector<int> *pvec_even,
vector<int> *pvec_odd )
{
// 必须声明一个const_iterator, 才能够遍历pvec
vector<int>::const_iterator c_iter = pvec->begin();
vector<int>::const_iterator c_iter_end = pvec->end();
for ( ; c_iter != c_iter_end; ++c_iter )
if ( *c_iter % 2 )
pvec_odd->push_back( *c_iter );
else pvec_even->push_back( *c_iter );
}
最后如果我们希望查看这些元素的某个子集该怎么办呢如每隔一个元素或每隔三
个元素或者从中间开始逐个访问元素我们可以用标量算术运算使iterator 从当前位置偏移
到某个位置上例如
vector<int>::iterator iter = vec.begin()+vec.size()/2;
将iter 指向vec 的中间元素而
iter += 2;
将iter 向前移动两个元素
iterator 算术论算只适用于vector 或deque 而不适用于list 因为list 的元素在内存中不
是连续存储的例如
ilist.begin() + 2;
是不正确的因为在list 中向前移动两个元素需要沿着内部next 指针走两次对于vector
或deque 前进两个元素需要把当前的地址值加上两个元素的长度3.3 节给出了关于指针算
术运算的讨论
容器对象也可以用由一对iterator 标记的起始元素和未元素后一位置之间的拷贝来初
始化例如假设我们有
#include <vector>
#include <string>
#include <iostream>
int main()
{
vector<string> svec;
string intext;
while ( cin >> intext )
svec.push_back( intext );
// process svec ...
}
我们可以定义一个新的vector 来拷贝svec 的全部或部分元素
int main()
{
vector<string> svec;
// ...
// 用svec 的全部元素初始化svec2
vector<string> svec2( svec.begin(), svec.end() );
// 用svec 的前半部分初始化svec3
vector<string>::iterator it =
svec.begin() + svec.size()/2;
vector<string> svec3( svec.begin(), it );
// 处理 vectors ...
}
用特定的istream_iterator 类型可以更直接地向svec 插入文
本元素
#include <vector>
#include <string>
#include < iterator >
int main()
{
// 将输入流iterator 绑定到标准输入上
istream_iterator<string> infile( cin );
// 标记流结束位置的输入流iterator
istream_iterator<string> eos;
// 利用通过cin 输入的值初始化svec
vector<string> svec( infile, eos );
// 处理 svec
}
除了一对iterator 之外两个指向内置数组的指针也可以被用作元素范围标记器range
marker 例如假设我们有下列string 对象的数组
#include <string>
string words[4] = {
"stately", "plump", "buck", "mulligan"
};
可以通过传递数组words 的首元素指针和末元素后一位置的指针来初始化string
vector
vector< string > vwords( words, words+4 );
第二个指针被用作终止条件它指向的对象通常指向容器或者数组中最后一个元素后
面的位置上不包含在要被拷贝或遍历的元素之中
类似地我们可以按如下方式初始化一个内含int 型元素的list
int ia[6] = { 0, 1, 2, 3, 4, 5 };
list< int > ilist( ia, ia+6 );