22

在 STL 库中,一些容器具有迭代器,并且通常认为它们是迭代这些容器的更好方法,而不是简单的 for 循环,例如

for ( int i=0; i < vecVector.size(); i++ )
{

..

}

谁能告诉我为什么以及在什么情况下我应该使用迭代器以及在什么情况下上面的代码片段?

4

6 回答 6

28

请注意,vector 的通常实现不会使用“int”作为索引/大小的类型。因此,您的代码至少会引发编译器警告。

通用性

迭代器增加了代码的通用性。

例如:

typedef std::vector<int> Container ;

void doSomething(Container & p_aC)
{
    for(Container::iterator it = p_aC.begin(), itEnd = p_aC.end(); it != itEnd; ++it)
    {
       int & i = *it ; // i is now a reference to the value iterated
       // do something with "i"
    }
}

现在,让我们假设您将向量更改为列表(因为在您的情况下,列表现在更好)。您只需要更改 typedef 声明,并重新编译代码。

如果您改用基于索引的代码,则需要重新编写它。

使用权

迭代器应该被视为一种超级指针。它“指向”值(或者,在映射的情况下,指向键/值对)。

但它具有移动到容器中下一个项目的方法。或者上一个。一些容器甚至提供随机访问(向量和双端队列)。

算法

大多数 STL 算法都适用于迭代器或迭代器范围(同样,因为通用性)。您将无法在此处使用索引。

于 2008-10-07T15:20:10.230 回答
17

使用迭代器可以让您的代码与容器的实现无关。如果您的容器的随机访问很便宜,那么在性能方面没有太大差异。

但在很多情况下,您不会知道是否是这种情况。如果您尝试在链接列表上使用您的方法,例如,使用下标,则容器将不得不在每次迭代时遍历列表以找到您的元素。

因此,除非您确定对容器的随机访问很便宜,否则请使用迭代器。

于 2008-10-07T15:14:31.817 回答
3

如果您使用迭代器作为函数的参数,您可以将其与所使用的“容器”类型分离。例如,您可以将函数的结果定向到控制台输出而不是向量(下面的示例)。这个技巧对于减少类之间的耦合非常有效。松散耦合的类更容易测试。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

template <typename InputIterator, typename OutputIterator>
void AddOne(InputIterator begin, InputIterator end, OutputIterator dest)
{
    while (begin != end)
    {
        *dest = *begin + 1;
        ++dest;
        ++begin;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    vector<int> data;
    data.push_back(1);
    data.push_back(2);
    data.push_back(3);

    // Compute intermediate results vector and dump to console
    vector<int> results;
    AddOne(data.begin(), data.end(), back_inserter(results));
    copy(results.begin(), results.end(), ostream_iterator<int>(cout, " "));
    cout << endl;

    // Compute results and send directly to console, no intermediate vector required
    AddOne(data.begin(), data.end(), ostream_iterator<int>(cout, " "));
    cout << endl;

    return 0;
}
于 2008-10-07T16:39:47.607 回答
2

在您的示例中,对 vecVector.size() 的调用效率低于使用迭代器。迭代器本质上使您不必担心被迭代的容器的大小。此外,迭代器不必按顺序进行。它只需要以它认为合适的任何方式响应 .next 调用。

于 2008-10-07T15:17:41.640 回答
1

好吧,一方面,如果您将该向量转换为列表,则上述内容将不再有效。

迭代器允许您创建不需要知道它们工作的容器类型的函数模板。您甚至可以执行以下操作:

#include <algorithm>

void printvalue(double s)
{
    // Do something with s
}

int _tmain(int argc, _TCHAR* argv[])
{
    double s[20] = {0};

    std::for_each(s, s+20, printvalue);

    return 0;
}

这是因为标准指针也是 for_each 的有效迭代器。

戴夫

于 2008-10-07T15:19:32.213 回答
1

迭代器主要是更高级别的抽象。

您的代码段假定容器可以被索引。这适用于std::vector<>其他一些容器,例如原始数组。

但是std::set<>完全没有索引,并且索引运算符std::map<>会将提供给它的任何参数插入到映射中 - 而不是您的for-loop 中的预期行为。

此外,性能问题只有在测量和证明时才是问题。

于 2008-10-08T08:28:30.250 回答