迭代程序在C++中的重要性

Importance of Iterators In C++

本文关键字:重要性 C++ 程序 迭代      更新时间:2023-10-16

这似乎是一个奇怪的问题,但我今天和一位朋友聊了聊,他对当今的C++程序员以及他们如何做得不太好大吵大闹。他说,他最讨厌的是在这样的代码中滥用迭代:

for(int i = 0; i<((int) someVector.size()); ++i){
    //Something here
}

而不是更传统的

vector::iterator i;
for(i = someVector.begin(); i!=someVector.end(); ++i){
    //Something here
}

虽然我理解这两种方法,但第二种方法优于第一种方法有什么特别的原因吗?是表演吗?还是其他因素?

提前谢谢。

这两种风格都不好。

第一个有一个无用和危险的演员阵容。

第二种方法允许迭代变量泄漏到循环的范围之外,并且不使用相等测试,而是在迭代器上使用后增量,这会产生无用的副本。

更好的是:

using std::begin, std::end;
for( auto it = begin(container), end_it = end(container); it != end_it; ++it )

这适用于任何STL容器、数组以及提供beginend辅助函数的任何容器。

对于vector,两者之间几乎没有区别。然而,如果您想迭代一个数据结构,比如set,它根本没有随机访问,那么使用迭代器的第二个选项将是唯一明智的选择。

C++标准库竭尽全力使"迭代器"接口在许多不同类型的容器上尽可能一致。

在某些数据结构中,计算大小可能效率低下。根据优化器所能做的工作,这可能最终会为循环的每次迭代调用size()方法。当你使用第二段代码时,你不依赖于调用一个方法来计算大小,而你真正想要的只是知道你是否已经到达了末尾。

例如,考虑一个链表。除非链表被设计为在内部保持计数,否则必须遍历整个列表才能找到大小。此外,对于数据结构,没有办法使用索引来获取值。在这种情况下,您必须使用正确的迭代器方法。

使用迭代器通常不会带来真正的性能提升。可能更少。然而,与迭代的"C方法"相比,它们有一些潜在的优势:

1) 通过迭代器抽象容器可能更容易。由于我们在每次迭代中都要处理一个指针,如果容器类型需要更改,并且通过索引访问元素的形式发生了变化(或者因为不可能随机访问而不可能),迭代器可以节省一些乏味的编辑。

2) 您可以避免在每次迭代中使用size()。尽管你可以预先计算一次,但最好完全避免。

3) 您基本上要处理一个指向正在遍历的容器中每个元素的指针。这比索引更好(至少对我来说是这样),而且可能更紧凑。

首先,我要注意的是,大多数代码根本不应该有显式循环。如果你要对一个集合进行操作,你应该使用一个算法。如果其中一个标准算法不能完成任务,你通常仍然应该实现你需要的算法,然后在需要的地方应用该算法(但如果你开始注意,你可能会惊讶于标准算法的工作频率)。

如果您确实需要编写一个显式循环,可以考虑使用基于范围的循环:

for (auto i : someVector)
    // ... 

然而,大多数时候,这应该是在算法的实现中。