C++迭代器分为输入、输出、前向、双向和随机访问五类,能力依次增强。输入迭代器支持单向读取,输出迭代器支持单向写入,前向迭代器支持多遍读写,双向迭代器可前后移动,随机访问迭代器支持任意位置跳转。这种分类使算法能根据所需最小能力选择合适迭代器,确保泛型编程的通用性、安全性和效率。例如,std::find只需输入迭代器,而std::sort要求随机访问迭代器。容器据此提供匹配迭代器,如vector支持随机访问,list仅支持双向遍历。自定义容器需通过iterator_category等typedef声明迭代器类型,以兼容标准库算法。

C++中的迭代器分类,本质上是对迭代器能力的一种抽象和规范。它定义了迭代器能执行哪些操作,不能执行哪些操作,从而让各种泛型算法能够以最通用且安全的方式工作。我们通常将迭代器分为五大类:输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器。每一种类别都代表了一组特定的操作集合,并且它们之间存在着一种层级关系,能力越强的迭代器,其所能支持的操作也越多。
理解C++迭代器分类,就好比理解不同工具箱里的工具。你不会指望一把螺丝刀能拧下六角螺栓,同样,你也不能指望一个只能单向读取的迭代器能随机跳跃。这种分类是C++泛型编程的基石,它确保了算法的通用性,同时又不会过度依赖特定容器的内部实现。
这是最基础的读取型迭代器。它的核心能力是“读取一次”和“单向前进”。你可以用
*it
it++
std::istream_iterator
关键特性:
立即学习“C++免费学习笔记(深入)”;
*it
it++
it == it2
it != it2
与输入迭代器相对,输出迭代器是“写入一次”和“单向前进”的。它的主要任务是将值写入到某个位置。同样,它也不保证多次解引用同一个迭代器(在递增后)会指向同一个有效写入位置。它不支持读取。
关键特性:
立即学习“C++免费学习笔记(深入)”;
*it = value
it++
前向迭代器是输入迭代器和输出迭代器能力的结合与增强。它既能读取也能写入(如果元素类型允许),并且最重要的是,它保证了“多遍遍历”的能力。这意味着你可以多次从头开始遍历一个序列,或者在递增后,再次解引用之前的迭代器仍然是有效的。它依然只能单向前进。
std::forward_list
关键特性:
立即学习“C++免费学习笔记(深入)”;
*it
双向迭代器在前向迭代器的基础上增加了“倒退”的能力。你可以用
it--
std::list
std::set
std::map
关键特性:
立即学习“C++免费学习笔记(深入)”;
it--
这是能力最强的迭代器类型,它在双向迭代器的基础上,增加了“随机访问”的能力,就像操作普通数组指针一样。你可以直接跳跃
n
it[n]
std::vector
std::deque
std::array
关键特性:
立即学习“C++免费学习笔记(深入)”;
it + n
it - n
it += n
it -= n
it < it2
it > it2
it <= it2
it >= it2
it[n]
it2 - it
difference_type
在我看来,这种分类设计非常精妙。它允许C++标准库算法根据它们所需的最小迭代器能力来声明要求,而不是强求所有容器都提供最强大的迭代器。这既保证了算法的通用性,又避免了对容器实现施加不必要的负担。
C++对迭代器进行分类,核心目的在于实现泛型编程的效率与安全性。这并非是某个开发者拍脑袋想出来的复杂设计,而是为了在高度抽象的算法与具体的数据结构之间搭建一座坚固的桥梁。
在我看来,这种分类机制主要带来了以下几个方面的影响:
std::sort
std::find
std::reverse
std::vector
std::list
std::find
std::sort
std::list
std::sort
std::list
std::list
std::list
std::vector
std::list
总而言之,迭代器分类是C++泛型编程哲学的一个缩影:在保证通用性的同时,通过精确的能力声明来确保效率和安全性。
选择合适的C++标准库算法,很大程度上就是匹配算法对迭代器能力的需求。这就像是给任务选择合适的工具:如果你要锯木头,你得用锯子,而不是锤子。标准库算法在它们的文档中(或通过其设计本身)明确了所需的迭代器类别。
以下是一些具体例子和我的思考:
std::find
std::count
std::vector
std::list
std::set
std::istream_iterator
std::list<int> my_list = {1, 2, 3, 4, 5};
auto it = std::find(my_list.begin(), my_list.end(), 3); // list的迭代器是双向的,但find只需要输入迭代器
if (it != my_list.end()) {
// 找到了
}std::fill
std::copy
std::fill
std::copy
std::vector<int> source = {1, 2, 3};
std::vector<int> dest(3);
std::copy(source.begin(), source.end(), dest.begin()); // vector迭代器是随机访问的,但copy只需要输入和输出迭代器std::for_each
std::vector<int> data = {1, 2, 3, 4, 5};
std::for_each(data.begin(), data.end(), [](int& n){ n *= 2; }); // vector迭代器是随机访问的,但for_each只需要前向迭代器std::reverse
std::vector
std::list
std::forward_list
std::list<int> another_list = {10, 20, 30};
std::reverse(another_list.begin(), another_list.end()); // list迭代器是双向的,满足要求
// std::forward_list<int> forward_list = {1,2,3};
// std::reverse(forward_list.begin(), forward_list.end()); // 编译错误!forward_list迭代器不是双向的std::sort
std::nth_element
std::list
std::sort
std::vector
std::list::sort()
std::vector<int> numbers = {5, 2, 8, 1, 9};
std::sort(numbers.begin(), numbers.end()); // vector迭代器是随机访问的,满足要求
// std::list<int> unsorted_list = {5, 2, 8};
// std::sort(unsorted_list.begin(), unsorted_list.end()); // 编译错误!list迭代器不是随机访问的我的经验是,当你对一个算法的功能有疑问时,查阅其文档是最好的方法。文档会明确指出它需要哪种迭代器类别。理解这些分类,不仅能帮助你避免编译错误,更能让你对算法的潜在性能有更清晰的认识。
如果你正在开发一个自定义容器,并希望它能与C++标准库的各种算法无缝协作,那么正确实现其迭代器是至关重要的一步。这不仅仅是实现
operator++
operator*
std::iterator_traits
iterator_category
我个人在实现自定义容器时,通常会遵循以下几个要点:
定义迭代器类及其基本成员: 你的迭代器需要是一个独立的类或结构体。它通常需要包含一个指向容器内部元素的指针或引用,以及实现必要的运算符。
声明 typedef
std::iterator_traits
typedef
value_type
int
difference_type
std::ptrdiff_t
pointer
value_type
int*
reference
value_type
int&
iterator_category
例如,如果你想实现一个前向迭代器:
#include <iterator> // 包含迭代器标签类型
template <typename T>
class MyForwardIterator {
public:
// 关键的typedef成员
using iterator_category = std::forward_iterator_tag; // 声明为前向迭代器
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using reference = T&;
// 构造函数
MyForwardIterator(T* ptr) : m_ptr(ptr) {}
// 解引用运算符
reference operator*() const { return *m_ptr; }
pointer operator->() const { return m_ptr; }
// 前进运算符
MyForwardIterator& operator++() { // 前置递增
++m_ptr;
return *this;
}
MyForwardIterator operator++(int) { // 后置递增
MyForwardIterator temp = *this;
++(*this);
return temp;
}
// 比较运算符
bool operator==(const MyForwardIterator& other) const { return m_ptr == other.m_ptr; }
bool operator!=(const MyForwardIterator& other) const { return !(*this == other); }
private:
T* m_ptr;
};选择正确的 iterator_category
std::input_iterator_tag
std::output_iterator_tag
std::forward_iterator_tag
std::bidirectional_iterator_tag
std::random_access_iterator_tag
如果你想让你的迭代器支持倒退,那么你需要将
iterator_category
std::bidirectional_iterator_tag
operator--()
std::random_access_iterator_tag
operator+
operator-
operator+=
operator-=
operator[]
实现必要的运算符: 根据你选择的
iterator_category
std::bidirectional_iterator_tag
operator--
std::random_access_iterator_tag
考虑 const
const
const_iterator
通过这种方式,你的自定义迭代器就能清晰地告诉C++标准库它具备哪些能力。当标准库算法需要一个特定类别的迭代器时,它会通过
std::iterator_traits
iterator_category
以上就是C++迭代器分类 五种迭代器特性对比的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号