Effective STL - 03 - Iterator

Iterator

条款26:尽量用iterator代替const_iterator,reverse_iterator和const_reverse_iterator

graph 
A[iterator] --> B[const_iterator]
A[iterator] --> C[reverse_iterator]
C[reverse_iterator] --> D[const_reverse_iterator]
C[reverse_iterator] -->|base| A[iterator]
D[const_reverse_iterator] -->|base| B[const_iterator]

iterator 能够比 const_iterator 有更好的泛化性能,特别是对于 inserterase 函数,他们只支持 iterator 而不支持 const_iterator。

我们已经有足够的理由相信应该尽量使用iterator取代const或者reverse类型的迭代器:

  • insert和erase的一些版本要求iterator。如果你需要调用这些函数,你就必须产生iterator,而不能用const或reverse iterators。
  • 不可能把const_iterator隐式转换成iterator,我们将会在条款27中讨论从一个const_iterator产生一个iterator的技术并不普遍适用,而且不保证高效。
  • 从reverse_iterator转换而来的iterator在转换之后可能需要相应的调整,在条款28中我们会讨论何时需要调整以及调整的原因。

条款27:用distance和advance把const_iterator转化成iterator

1
2
3
4
5
6
7
8
9
10
11
12
13
vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

vector<int>::iterator it = v.begin() + 3;
auto ci = static_cast<vector<int>::const_iterator>(it);
// auto it2 = static_cast<vector<int>::iterator>(ci); // 不支持

auto it2 = v.begin();
// advance: increment iterator by offset
// distance: find difference of two iterators
// 根据距离移动对应的指针
// 但是实际运行起来报错了 ....
// advance(it2, distance<decltype(ci)>(ci, it2));
advance(it2, ci - it2);

条款28:了解如何通过reverse_iterator的base得到iterator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
cout << v << endl;

// 插入 ri 时, 插入发生在 ri 指向的正向下一个元素
// {0,1,2,3,4,5,6,7,8,9} -> {0,1,2,3,4,5,6, 5 ,7,8,9}
auto ri = v.rbegin() + 3;
cout << *ri << endl;
v.insert(ri.base(), 5);
cout << v << endl;

// 删除 ri 时, 删除发生在 ri 指向的正向下一个元素
// {0,1,2,3,4,5,6,5,7,8,9} -> {0,1,2,3,4,5,6,5 , 8,9}
ri = v.rbegin() + 3;
v.erase(ri.base());
cout << v << endl;

总结:**ri.base() 永远返回指向 ri 的正向下一个元素。因此,对于 逆向的 insert 来说,插入刚好发生在 ri 的逆向上一个元素;对于 逆向的 erase 来说,删除刚好发生在 ri 的逆向上一个元素,并不像 iterator 那样删除本身**。

条款29:需要一个一个字符输入时考虑使用istreambuf_iterator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 使用 istream_iterator
// 输出: HelloWorld
// 35ms
istringstream iss("Hello World");
istream_iterator<char> iic(iss), eof1;
string s1(iic, eof1);
cout << "string read by istream_iterator: " << s1 << endl;

// 使用 istreambuf_iterator
// 输出: Hello World
// 18ms
istringstream iss2("Hello World");
istreambuf_iterator<char> ibic(iss2), eof2;
string s2(ibic, eof2);
cout << "string read by istreambuf_iterator: " << s2 << endl;

使用 istreambuf_iterator 比 istream_iterator 快了大约一半。

istream_iterator 使用了 operator>> 来读取输入,因此能够设置模式化读入;istream_iterator 使用了 cin.getchar() 读取,所以对于读取单个的字符会更快。


Effective STL - 03 - Iterator
http://hebangwen.github.io/2024/03/17/Iterator/
作者
何榜文
发布于
2024年3月17日
许可协议