C++ 为什么使用迭代器而不是数组索引?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/131241/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:05:33  来源:igfitidea点击:

Why use iterators instead of array indices?

c++for-loopstliteratorcontainers

提问by Jason Baker

Take the following two lines of code:

取以下两行代码:

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

And this:

和这个:

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

I'm told that the second way is preferred. Why exactly is this?

有人告诉我,第二种方式是首选。这是为什么?

采纳答案by wilhelmtell

The first form is efficient only if vector.size() is a fast operation. This is true for vectors, but not for lists, for example. Also, what are you planning to do within the body of the loop? If you plan on accessing the elements as in

只有当 vector.size() 是一个快速操作时,第一种形式才有效。例如,这适用于向量,但不适用于列表。另外,你打算在循环体内做什么?如果您打算像这样访问元素

T elem = some_vector[i];

then you're making the assumption that the container has operator[](std::size_t)defined. Again, this is true for vector but not for other containers.

那么你就假设容器已经operator[](std::size_t)定义了。同样,这对于 vector 是正确的,但对于其他容器则不然。

The use of iterators bring you closer to container independence. You're not making assumptions about random-access ability or fast size()operation, only that the container has iterator capabilities.

迭代器的使用使您更接近容器独立性。您没有对随机访问能力或快速size()操作做出假设,只是假设容器具有迭代器功能。

You could enhance your code further by using standard algorithms. Depending on what it is you're trying to achieve, you may elect to use std::for_each(), std::transform()and so on. By using a standard algorithm rather than an explicit loop you're avoiding re-inventing the wheel. Your code is likely to be more efficient (given the right algorithm is chosen), correct and reusable.

您可以使用标准算法进一步增强您的代码。根据您要实现的目标,您可以选择使用std::for_each()std::transform()依此类推。通过使用标准算法而不是显式循环,您可以避免重新发明轮子。您的代码可能更高效(如果选择了正确的算法)、正确且可重用。

回答by cruizer

because you are not tying your code to the particular implementation of the some_vector list. if you use array indices, it has to be some form of array; if you use iterators you can use that code on any list implementation.

因为您没有将代码绑定到 some_vector 列表的特定实现。如果你使用数组索引,它必须是某种形式的数组;如果您使用迭代器,您可以在任何列表实现上使用该代码。

回答by Mark Ransom

It's part of the modern C++ indoctrination process. Iterators are the only way to iterate most containers, so you use it even with vectors just to get yourself into the proper mindset. Seriously, that's the only reason I do it - I don't think I've ever replaced a vector with a different kind of container.

它是现代 C++ 灌输过程的一部分。迭代器是迭代大多数容器的唯一方法,因此即使与向量一起使用,也只是为了让自己进入正确的心态。说真的,这是我这样做的唯一原因——我认为我从来没有用不同类型的容器替换过向量。



哇,这在三周后仍然被否决了。我想说一点半开玩笑是不值得的。

I think the array index is more readable. It matches the syntax used in other languages, and the syntax used for old-fashioned C arrays. It's also less verbose. Efficiency should be a wash if your compiler is any good, and there are hardly any cases where it matters anyway.

我认为数组索引更具可读性。它与其他语言中使用的语法以及用于老式 C 数组的语法相匹配。它也不太冗长。如果您的编译器很好,效率应该是一种洗礼,而且几乎没有任何情况下它很重要。

Even so, I still find myself using iterators frequently with vectors. I believe the iterator is an important concept, so I promote it whenever I can.

即便如此,我仍然发现自己经常使用带有向量的迭代器。我相信迭代器是一个重要的概念,所以我会尽可能地推广它。

回答by asterite

Imagine some_vector is implemented with a linked-list. Then requesting an item in the i-th place requires i operations to be done to traverse the list of nodes. Now, if you use iterator, generally speaking, it will make its best effort to be as efficient as possible (in the case of a linked list, it will maintain a pointer to the current node and advance it in each iteration, requiring just a single operation).

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

So it provides two things:

所以它提供了两件事:

  • Abstraction of use: you just want to iterate some elements, you don't care about how to do it
  • Performance
  • 使用抽象:你只想迭代一些元素,你不关心如何去做
  • 表现

回答by Chad

I'm going to be the devils advocate here, and not recommend iterators. The main reason why, is all the source code I've worked on from Desktop application development to game development have i nor have i needed to use iterators. All the time they have not been required and secondly the hidden assumptions and code mess and debugging nightmares you get with iterators make them a prime example not to use it in any applications that require speed.

我将在这里成为魔鬼的拥护者,而不是推荐迭代器。主要原因是我从桌面应用程序开发到游戏开发的所有源代码都不需要使用迭代器。一直以来都不需要它们,其次,迭代器带来的隐藏假设和代码混乱以及调试噩梦使它们成为最好的例子,不要在任何需要速度的应用程序中使用它。

Even from a maintence stand point they're a mess. Its not because of them but because of all the aliasing that happen behind the scene. How do i know that you haven't implemented your own virtual vector or array list that does something completely different to the standards. Do i know what type is currently now during runtime? Did you overload a operator I didn't have time to check all your source code. Hell do i even know what version of the STL your using?

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

The next problem you got with iterators is leaky abstraction, though there are numerous web sites that discuss this in detail with them.

迭代器的下一个问题是抽象泄漏,尽管有许多网站与它们详细讨论了这个问题。

Sorry, I have not and still have not seen any point in iterators. If they abstract the list or vector away from you, when in fact you should know already what vector or list your dealing with if you don't then your just going to be setting yourself up for some great debugging sessions in the future.

抱歉,我还没有看到迭代器中有任何意义。如果他们从您那里抽象出列表或向量,而实际上您应该已经知道要处理的向量或列表,如果您不知道,那么您只会为将来的一些出色的调试会话做好准备。

回答by Brian Matthews

You might want to use an iterator if you are going to add/remove items to the vector while you are iterating over it.

如果您要在迭代时向矢量添加/删除项目,您可能需要使用迭代器。

some_iterator = some_vector.begin(); 
while (some_iterator != some_vector.end())
{
    if (/* some condition */)
    {
        some_iterator = some_vector.erase(some_iterator);
        // some_iterator now positioned at the element after the deleted element
    }
    else
    {
        if (/* some other condition */)
        {
            some_iterator = some_vector.insert(some_iterator, some_new_value);
            // some_iterator now positioned at new element
        }
        ++some_iterator;
    }
}

If you were using indices you would have to shuffle items up/down in the array to handle the insertions and deletions.

如果您使用索引,则必须在数组中向上/向下移动项目以处理插入和删除。

回答by xtofl

Separation of Concerns

关注点分离

It's very nice to separate the iteration code from the 'core' concern of the loop. It's almost a design decision.

将迭代代码与循环的“核心”关注点分开是非常好的。这几乎是一个设计决定。

Indeed, iterating by index ties you to the implementation of the container. Asking the container for a begin and end iterator, enables the loop code for use with other container types.

事实上,按索引迭代将您与容器的实现联系起来。向容器询问开始和结束迭代器,启用循环代码以与其他容器类型一起使用。

Also, in the std::for_eachway, you TELL the collection what to do, instead of ASKingit something about its internals

此外,std::for_each顺便说一下,你告诉集合要做什么,而不是询问它的内部结构

The 0x standard is going to introduce closures, which will make this approach much more easy to use - have a look at the expressive power of e.g. Ruby's [1..6].each { |i| print i; }...

0x 标准将引入闭包,这将使这种方法更易于使用 - 看看例如 Ruby 的[1..6].each { |i| print i; }...

Performance

表现

But maybe a much overseen issue is that, using the for_eachapproach yields an opportunity to have the iteration parallelized - the intel threading blockscan distribute the code block over the number of processors in the system!

但也许一个备受关注的问题是,使用这种for_each方法可以让迭代并行化——英特尔线程块可以在系统中的处理器数量上分配代码块!

Note: after discovering the algorithmslibrary, and especially foreach, I went through two or three months of writing ridiculously small 'helper' operator structs which will drive your fellow developers crazy. After this time, I went back to a pragmatic approach - small loop bodies deserve no foreachno more :)

注意:在发现这个algorithms库,尤其是 之后foreach,我经历了两三个月的时间,编写了可笑的小“助手”操作符结构,这会让你的开发伙伴们发疯。这一次之后,我又回到了一种务实的方法——小循环体不再值得foreach了:)

A must read reference on iterators is the book "Extended STL".

关于迭代器的必读参考书是“扩展 STL”一书。

The GoF have a tiny little paragraph in the end of the Iterator pattern, which talks about this brand of iteration; it's called an 'internal iterator'. Have a look here, too.

GoF 在 Iterator 模式的末尾有一个很小的段落,它谈到了这个品牌的迭代;它被称为“内部迭代器”。也看看这里

回答by Pat Notz

Another nice thing about iterators is that they better allow you to express (and enforce) your const-preference. This example ensures that you will not be altering the vector in the midst of your loop:

迭代器的另一个好处是它们更好地允许您表达(并强制执行)您的常量偏好。此示例确保您不会在循环中间更改向量:


for(std::vector<Foo>::const_iterator pos=foos.begin(); pos != foos.end(); ++pos)
{
    // Foo & foo = *pos; // this won't compile
    const Foo & foo = *pos; // this will compile
}

回答by Pat Notz

Aside from all of the other excellent answers... intmay not be large enough for your vector. Instead, if you want to use indexing, use the size_typefor your container:

除了所有其他优秀的答案......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
}

回答by cynicalman

Because it is more object-oriented. if you are iterating with an index you are assuming:

因为它更面向对象。如果您正在使用索引进行迭代,则您假设:

a) that those objects are ordered
b) that those objects can be obtained by an index
c) that the index increment will hit every item
d) that that index starts at zero

a) 这些对象是有序的
b) 这些对象可以通过索引获得
c) 索引增量将命中每个项目
d) 该索引从零开始

With an iterator, you are saying "give me everything so I can work with it" without knowing what the underlying implementation is. (In Java, there are collections that cannot be accessed through an index)

使用迭代器,您会说“给我一切,以便我可以使用它”而不知道底层实现是什么。(在Java中,有些集合是不能通过索引访问的)

Also, with an iterator, no need to worry about going out of bounds of the array.

此外,使用迭代器,无需担心超出数组范围。