简体   繁体   English

使用标准的标准容器进行迭代

[英]iterating over std containers using standard for

From what I've learned the way to iterating over container, as std::vector, is by using iterators, as this: 从我学到的以std :: vector遍历容器的方式是使用迭代器,如下所示:

for(vector<int>::iterator it = numbers.begin(); it != numbers.end(); it++)

My question is why not not iterating over container with standatd for , it is faster, because there is no need to call functions as numbers.begin() , and numbers.end() . 我的问题是,为什么不使用standatd for而不是在容器上for迭代,它更快,因为不需要调用numbers.begin()numbers.end()函数。
From what I tried, I found that using for is faster X 30, from using iterators. 从我的尝试中,我发现使用for的速度比使用迭代器的速度快X 30。
I wrote this code: 我写了这段代码:

vector<int> numbers;
for (int i = 0; i < 5000000; i++)
{
    numbers.push_back(i);
}

time_t t = time(0);
struct tm * now = localtime(&t);
cout << now->tm_hour << ":" << now->tm_min << ":" <<  now->tm_sec << "\n";

for(vector<int>::iterator it = numbers.begin(); it != numbers.end(); it++)
{
    *it = 7;
}

t = time(0);
now = localtime(&t);
cout << now->tm_hour << ":" << now->tm_min << ":" <<  now->tm_sec << "\n";

int size = numbers.size();
for (int i = 0; i < size; i++)
{
    numbers[i] = i;
}

t = time(0);
now = localtime(&t);
cout << now->tm_hour << ":" << now->tm_min << ":" <<  now->tm_sec;

The output is: 输出为:

    19:28:25
    19:28:56
    19:28:57

Look at your numbers -- 30 seconds to iterate a simple vector? 看一下您的数字-30秒迭代一个简单的向量? That's an eternity in CPU time. 那是CPU时间的永恒。 There's something wrong there. 那里出问题了。

Some suggestions: 一些建议:

  • The vector takes ~19MB. 该载体大约需要19MB。 That's not much but it's possible that it could cause heap fragmentation, or maybe VM swapping if you had many other apps loaded on your computer. 数量不多,但是有可能导致堆碎片,或者如果计算机上加载了许多其他应用程序,则可能导致VM交换。 To get a reliable number, close as many apps as possible and make sure your system is idle. 为了获得可靠的数字,请关闭尽可能多的应用程序,并确保系统空闲。

  • The couts are inside the timer, so you're measuring the performance of parts of the iostream library. 提示位于计时器内部,因此您正在测量iostream库的各个部分的性能。 Do the couts outside the timed section, after you take the stop time. 您停下时间之后计时部分之外进行侦察。

  • A one-second clock isn't precise enough for performance metrics. 一秒钟的时钟不够精确,无法衡量性能指标。 Use timeval and gettimeofday() to get micro-second precision. 使用timeval和gettimeofday()获得微秒精度。

  • With only one iteration of the vector, I was seeing big diffences between runs. 仅对向量进行一次迭代,我就发现运行之间存在很大差异。 To get more repeatable results, iterate the vector multiple times (like 500 times). 为了获得更多可重复的结果,请多次迭代向量(例如500次)。 (This is better than using a larger vector, which might cause swapping/fragmentation issues.) (这比使用较大的向量更好,后者可能会导致交换/碎片问题。)

  • Turn on optimizations (eg, g++ -O3). 打开优化(例如g ++ -O3)。 The loops will ran much faster and the time difference will be much less. 循环运行得更快,时间差也要少得多。 Inline optimizations probably help the std::vector<> code more. 内联优化可能更有助于std :: vector <>代码。

With these changes (below), on my computer, iterators were 4x slower than indicies without optimizations but slightly faster with -O1 and pretty much the same with -O3. 有了这些更改(如下),在我的计算机上,迭代器的速度比没有优化的索引慢4倍,但使用-O1的迭代器要快一些 ,而使用-O3的迭代器则差不多。

#include <iostream>
#include <sys/time.h>
#include <vector>
using namespace std;

const unsigned N_REPS = 500;
const unsigned N_ITEMS = 5000000;

int print_elapsed(timeval start)
{
    timeval stop;
    gettimeofday(&stop, NULL);
    int elapsed = (stop.tv_sec * 1000000 + stop.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec);
    cout << elapsed << "us" << endl;
    return elapsed;
}

int main()
{
    vector<int> numbers;
    numbers.reserve(N_ITEMS); // avoid heap fragmentation
    for (int i = 0; i < N_ITEMS; ++i)
        numbers.push_back(i);

    timeval start;
    gettimeofday(&start, NULL);

    for (unsigned r = 0; r < N_REPS; ++r)
        for (vector<int>::iterator it = numbers.begin(); it != numbers.end(); ++it)
            *it = r;

    int elapsed0 = print_elapsed(start);
    gettimeofday(&start, NULL);

    unsigned size = numbers.size();
    for (unsigned r = 0; r < N_REPS; ++r)
        for (unsigned i = 0; i < size; ++i)
            numbers[i] = r;

    int elapsed1 = print_elapsed(start);
    cout << 100 * float(elapsed1) / elapsed0 << '%' << endl;

    return 0;
}

Using iterators provide you the flexibility that even if you change the container type to another the iterating code will remain the same. 使用迭代器可为您提供灵活性,即使您将容器类型更改为另一种,迭代代码也将保持不变。 This is because all the standard library containers provide iterators. 这是因为所有标准库容器都提供了迭代器。 In a way it gives you the chance to write more generic code. 在某种程度上,它使您有机会编写更多通用代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM