以下面两行代码为例:
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
}
有人告诉我第二种方法更可取。为什么会这样呢?
以下面两行代码为例:
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
}
有人告诉我第二种方法更可取。为什么会这样呢?
当前回答
我不认为这对向量有多大区别。我更喜欢自己使用索引,因为我认为它更具可读性,你可以做随机访问,如向前跳转6个项目或向后跳转,如果需要的话。
我还喜欢像这样引用循环内的项目,这样在位置周围就不会有很多方括号:
for(size_t i = 0; i < myvector.size(); i++)
{
MyClass &item = myvector[i];
// Do stuff to "item".
}
使用迭代器可以很好,如果你认为你可能需要在未来的某个时候用一个列表替换向量,它也看起来更时尚的STL怪胎,但我想不出任何其他原因。
其他回答
假设some_vector是用链表实现的。然后,在第i个位置请求一个项需要执行i个操作来遍历节点列表。现在,如果您使用迭代器,一般来说,它将尽最大努力尽可能高效(在链表的情况下,它将维护一个指向当前节点的指针,并在每次迭代中推进它,只需要一个操作)。
所以它提供了两件事:
使用的抽象:你只想迭代一些元素,你不关心如何去做 性能
分离关注点
将迭代代码从循环的“核心”关注点中分离出来是非常好的。这几乎是一个设计决策。
实际上,通过索引迭代将您与容器的实现联系在一起。向容器请求开始和结束迭代器,使循环代码可用于其他容器类型。
同样,在std::for_each方法中,你告诉集合要做什么,而不是询问它的内部信息
0x标准将引入闭包,这将使这种方法更容易使用-看看例如Ruby的[1..6]的表达能力。每个{|i| print i;}……
性能
但是可能有一个被监督的问题是,使用for_each方法产生了一个并行迭代的机会——intel线程块可以将代码块分布在系统中的处理器数量上!
注意:在发现算法库,特别是foreach之后,我花了两三个月的时间写了非常小的“helper”操作符结构,这会让其他开发人员发疯。在这之后,我回到了一个实用的方法-小循环体不应该再有foreach了:)
关于迭代器的必读参考书是《扩展STL》。
GoF在迭代器模式的末尾有一小段话,讲的是这种迭代;它被称为“内部迭代器”。这里也看看。
我不使用迭代器的原因与我不喜欢foreach-statements的原因相同。当有多个内部循环时,如果不记住所有的局部值和迭代器名称,就很难跟踪全局/成员变量。我发现有用的是在不同的情况下使用两组指标:
for(int i=0;i<anims.size();i++)
for(int j=0;j<bones.size();j++)
{
int animIndex = i;
int boneIndex = j;
// in relatively short code I use indices i and j
... animation_matrices[i][j] ...
// in long and complicated code I use indices animIndex and boneIndex
... animation_matrices[animIndex][boneIndex] ...
}
例如,我甚至不想将“animation_matrices[I]”缩写为一些随机的“anim_matrix”-name -iterator,因为这样你就不能清楚地看到这个值来自哪个数组。
除了所有其他优秀的答案之外……Int对向量来说可能不够大。相反,如果你想使用索引,使用size_type为你的容器:
for (std::vector<Foo>::size_type i = 0; i < myvector.size(); ++i)
{
Foo& this_foo = myvector[i];
// Do stuff with this_foo
}
只有当vector.size()是一个快速操作时,第一种形式才有效。这对于向量是正确的,但是对于列表就不是这样了。另外,您计划在循环体中做什么?如果您计划访问元素,如
T elem = some_vector[i];
然后假设容器定义了operator[](std::size_t)。同样,这适用于vector容器,但不适用于其他容器。
迭代器的使用使您更接近容器独立性。您没有假设随机访问能力或快速size()操作,只是假设容器具有迭代器功能。
您可以通过使用标准算法进一步增强代码。根据你想要实现的目标,你可以选择使用std::for_each(), std::transform()等等。通过使用标准算法而不是显式循环,您可以避免重新发明轮子。您的代码可能更高效(如果选择了正确的算法)、正确和可重用。