以下面两行代码为例:

for (int i = 0; i < some_vector.size(); i++)
{
    //do stuff
}

这:

for (some_iterator = some_vector.begin(); some_iterator != some_vector.end();
    some_iterator++)
{
    //do stuff
}

有人告诉我第二种方法更可取。为什么会这样呢?


当前回答

分离关注点

将迭代代码从循环的“核心”关注点中分离出来是非常好的。这几乎是一个设计决策。

实际上,通过索引迭代将您与容器的实现联系在一起。向容器请求开始和结束迭代器,使循环代码可用于其他容器类型。

同样,在std::for_each方法中,你告诉集合要做什么,而不是询问它的内部信息

0x标准将引入闭包,这将使这种方法更容易使用-看看例如Ruby的[1..6]的表达能力。每个{|i| print i;}……

性能

但是可能有一个被监督的问题是,使用for_each方法产生了一个并行迭代的机会——intel线程块可以将代码块分布在系统中的处理器数量上!

注意:在发现算法库,特别是foreach之后,我花了两三个月的时间写了非常小的“helper”操作符结构,这会让其他开发人员发疯。在这之后,我回到了一个实用的方法-小循环体不应该再有foreach了:)

关于迭代器的必读参考书是《扩展STL》。

GoF在迭代器模式的末尾有一小段话,讲的是这种迭代;它被称为“内部迭代器”。这里也看看。

其他回答

我不认为这对向量有多大区别。我更喜欢自己使用索引,因为我认为它更具可读性,你可以做随机访问,如向前跳转6个项目或向后跳转,如果需要的话。

我还喜欢像这样引用循环内的项目,这样在位置周围就不会有很多方括号:

for(size_t i = 0; i < myvector.size(); i++)
{
    MyClass &item = myvector[i];

    // Do stuff to "item".
}

使用迭代器可以很好,如果你认为你可能需要在未来的某个时候用一个列表替换向量,它也看起来更时尚的STL怪胎,但我想不出任何其他原因。

假设some_vector是用链表实现的。然后,在第i个位置请求一个项需要执行i个操作来遍历节点列表。现在,如果您使用迭代器,一般来说,它将尽最大努力尽可能高效(在链表的情况下,它将维护一个指向当前节点的指针,并在每次迭代中推进它,只需要一个操作)。

所以它提供了两件事:

使用的抽象:你只想迭代一些元素,你不关心如何去做 性能

我在这里是魔鬼的倡导者,不推荐使用迭代器。主要原因是,我从桌面应用程序开发到游戏开发的所有源代码都没有我也不需要使用迭代器。一直以来,迭代器都不是必需的,其次,迭代器所带来的隐藏假设、代码混乱和调试噩梦,使其成为任何要求速度的应用程序都不要使用的典型例子。

即使从维护的角度来看,它们也是一团糟。这并不是因为它们,而是因为所有发生在幕后的混叠。我怎么知道你没有实现你自己的虚拟向量或数组列表,做一些完全不同的标准。我知道什么类型的当前,现在在运行时?你是否重载了运算符我没有时间检查你所有的源代码。我甚至不知道你使用的STL是什么版本?

迭代器的下一个问题是抽象漏洞,尽管有许多网站对此进行了详细讨论。

对不起,我没有,现在也没有看到迭代器有任何意义。如果他们抽象了列表或向量,而实际上你应该已经知道你要处理什么向量或列表,如果你不知道,那么你只会为将来的一些伟大的调试会话做好准备。

如果你可以访问c++ 11的特性,那么你也可以使用一个基于范围的for循环来迭代你的vector(或任何其他容器),如下所示:

for (auto &item : some_vector)
{
     //do stuff
}

这个循环的好处是,您可以直接通过item变量访问vector的元素,而不会有搞乱索引或在解引用迭代器时出错的风险。此外,占位符auto可以防止您重复容器元素的类型, 这使您更接近于容器无关的解决方案。

注:

如果您需要循环中的元素索引,并且容器中存在操作符[](并且对您来说足够快),那么最好采用第一种方法。 基于范围的for循环不能用于在容器中添加/删除元素。如果你想这样做,那么最好坚持布莱恩·马修斯给出的解决方案。 如果你不想改变容器中的元素,那么你应该如下所示使用关键字const: for (auto const &item: some_vector){…}。

在迭代过程中,您不需要知道要处理的项目的数量。你只需要item和迭代器就能很好地完成这些事情。