目录
1 概述
迭代器是指任何指向元素范围(如数组或容器)中某个元素的对象,该对象能够使用一组运算符(至少使用增量(++)和取消引用(*)运算符)在该范围的元素中进行迭代。
迭代器最明显的形式是指针:指针可以指向数组中的元素,并可以使用增量运算符(++)对它们进行迭代。但是其他类型的迭代器也是可能的。例如,每个容器类型(如列表)都有一个特定的迭代器类型,用于遍历其元素。
请注意,虽然指针是迭代器的一种形式,但并非所有迭代器都具有相同的指针功能;根据迭代器支持的属性,它们分为五个不同的类别:
- Input 输入迭代器是可以在顺序输入操作中使用的迭代器,其中迭代器指向的每个值只读取一次,然后迭代器递增。
- Forward 前向迭代器作为迭代器,可用于访问范围内从开始到结束的元素序列。
- Bidirectional 双向迭代器是一种迭代器,可用于在两个方向(朝向末尾和开头)访问范围内的元素序列。
- Random-access 随机访问迭代器是一种迭代器,可用于访问相对于所指向元素的任意偏移位置的元素,提供与指针相同的功能。
- Output 输出迭代器是可用于顺序输出操作的迭代器,其中迭代器指向的每个元素只写入一次值,然后迭代器递增。
2 分类
2.1 前向迭代器
- std::forward_list
- std::unordered_map
- std::unordered_multimap
- std::unordered_set
- std::unordered_multiset
2.2 双向迭代器
- std::list
- std::map
- std::multi_map
- std::set
- std::multi_set
2.3 随机访问迭代器
- std::array
- std::deque
- std::vector
3 接口
3.1 advance
使迭代器前进n个元素位置。
void IteratorSuite::advance()
{
std::list<int> a = { 0, 1, 2, 3, 4, 5 };
auto it = a.begin();
std::advance(it, 3);
TEST_ASSERT_EQUALS(3, *it)
std::advance(it, 1);
TEST_ASSERT_EQUALS(4, *it)
std::advance(it, 1);
TEST_ASSERT_EQUALS(5, *it)
std::advance(it, 1);
TEST_ASSERT_EQUALS(true, it == a.end())
}
说明:
- 如果它是一个随机访问迭代器,则函数只使用一次运算符+或运算符-。
- 否则,函数会重复使用递增或递减运算符(运算符++或运算符-),直到n个元素被推进。
- 参数应至少是一个输入迭代器。
3.2 distance
计算介于第一个和最后一个迭代器之间的元素数。
void IteratorSuite::distance()
{
std::vector<int> a = { 0, 1, 2, 3, 4, 5 };
std::forward_list<int> b = { 0, 1, 2, 3, 4, 5 };
auto size = std::distance(a.begin(), a.end());
TEST_ASSERT_EQUALS(6, size)
size = std::distance(b.begin(), b.end());
TEST_ASSERT_EQUALS(6, size)
}
说明:
- 如果它是一个随机访问迭代器,则函数只使用一次运算符-。
- 否则,该函数将重复使用递增运算符(运算符++)。
- 参数应至少是一个输入迭代器。
3.3 begin
返回一个迭代器,该迭代器指向序列中的第一个元素:
void IteratorSuite::begin()
{
int array[] = { 1, 2, 3, 4, 5, 6 };
std::vector<int> a;
auto begin = std::begin(array);
auto end = std::end(array);
a.reserve(std::distance(begin, end));
for(auto it = begin; it != end; ++it)
a.push_back(*it);
int index = 0;
for(auto i : a)
TEST_ASSERT_EQUALS(array[index++], i)
}
说明:
- 支持容器与数组
- 如果是容器,该函数返回container.begin()
- 如果是数组,该函数返回其参数的数组到指针的转换。
3.4 end
返回一个迭代器,该迭代器指向序列中最后一个元素后面的位置。
void IteratorSuite::end()
{
int array[] = { 1, 2, 3, 4, 5, 6 };
std::vector<int> a;
auto begin = std::begin(array);
auto end = std::end(array);
a.reserve(std::distance(begin, end));
for(auto it = begin; it != end; ++it)
a.push_back(*it);
int index = 0;
for(auto i : a)
TEST_ASSERT_EQUALS(array[index++], i)
}
- 支持容器与数组
- 如果是容器,该函数返回container.end()
- 如果是数组,该函数返回array + N。
3.5 prev
返回一个迭代器,该迭代器指向在advance(-n)位置时它将指向的元素。
void IteratorSuite::prev()
{
std::list<int> a = { 0, 1, 2, 3, 4, 5 };
auto it = std::prev(a.end());
TEST_ASSERT_EQUALS(5, *it)
it = std::prev(it, 2);
TEST_ASSERT_EQUALS(3, *it)
}
说明:
- 如果它是一个随机访问迭代器,则函数只使用一次运算符+或运算符-。
- 否则,该函数会在复制的迭代器上重复使用递增或递减运算符(运算符++或运算符–),直到n个元素被推进。
- 参数应至少是一个双向迭代器。
3.6 next
返回一个迭代器,该迭代器指向在advance(n)位置时要指向的元素。
void IteratorSuite::next()
{
std::list<int> a = { 0, 1, 2, 3, 4, 5 };
auto it = std::next(a.begin(), 3);
TEST_ASSERT_EQUALS(3, *it)
it = std::next(it);
TEST_ASSERT_EQUALS(4, *it)
it = std::next(it);
TEST_ASSERT_EQUALS(5, *it)
it = std::next(it);
TEST_ASSERT_EQUALS(true, it == a.end())
}
- 如果它是一个随机访问迭代器,则函数只使用一次运算符+或运算符-。
- 否则,该函数会在复制的迭代器上重复使用递增或递减运算符(运算符++或运算符–),直到n个元素被推进。
- 参数应至少是一个前向迭代器。
3.7 back_inserter
构造一个后插入迭代器,在x的末尾插入新元素。
void IteratorSuite::back_inserter()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::list<int> a = { 1, 2, 3, 4, 5 };
std::list<int> b = { 6, 7, 8, 9, 10 };
std::copy(b.begin(), b.end(), std::back_inserter(a));
int index = 0;
for(auto it = a.begin(); it != a.end(); ++it)
TEST_ASSERT_EQUALS(array[index++], *it)
}
说明:
- 容器需要有push_back接口
3.8 front_inserter
构造一个前插入迭代器,在x的开头插入新元素。
void IteratorSuite::front_inserter()
{
int array[] = { 5, 4, 3, 2, 1, 6, 7, 8, 9, 10 };
std::list<int> a = { 1, 2, 3, 4, 5 };
std::list<int> b = { 6, 7, 8, 9, 10 };
std::copy(a.begin(), a.end(), std::front_inserter(b));
int index = 0;
for(auto it = b.begin(); it != b.end(); ++it)
TEST_ASSERT_EQUALS(array[index++], *it)
}
说明:
- 容器需要有push_front接口
3.9 inserter
构造一个插入迭代器,从x指向的位置开始,在连续的位置将新元素插入到x中。
void IteratorSuite::inserter()
{
int array[] = { 6, 7, 8, 1, 2, 3, 4, 5, 9, 10 };
std::list<int> a = { 1, 2, 3, 4, 5 };
std::list<int> b = { 6, 7, 8, 9, 10 };
auto it = std::next(b.begin(), 3);
std::copy(a.begin(), a.end(), std::inserter(b, it));
int index = 0;
TEST_ASSERT_EQUALS(5, a.size())
for(auto it = b.begin(); it != b.end(); ++it)
TEST_ASSERT_EQUALS(array[index++], *it)
}
说明:
- 容器需要有insert接口
3.10 make_move_iterator
move_iterator是一个迭代器适配器,它对迭代器(it)进行适配,以便取消对它的引用产生右值引用(就像应用了std::move一样),而所有其他操作的行为都相同。
void IteratorSuite::make_move_iterator()
{
std::string array[] = { "a", "b", "c" };
std::list<std::string> a(3);
std::list<std::string> b{"a", "b", "c"};
std::copy(std::make_move_iterator(b.begin()),
std::make_move_iterator(b.end()), a.begin());
TEST_ASSERT_EQUALS(3, b.size())
TEST_ASSERT_EQUALS(3, a.size())
int index = 0;
for(auto s : a)
TEST_ASSERT_EQUALS(array[index++], s)
for(auto s : b)
TEST_ASSERT_EQUALS(true, s.empty())
}
说明:
- 调用make_move_iterator后迭代器变为move_iterator类型,赋值操作变成移动赋值操作。
- 如上容器b中元素变成空元素