简体   繁体   English

通过迭代器和运算符[] / index快速访问std :: vector?

[英]Speed accessing a std::vector by iterator vs by operator[]/index?

Say, I have a 说,我有一个

std::vector<SomeClass *> v;

in my code and I need to access its elements very often in the program, looping them forward and backward . 在我的代码中,我需要经常在程序中访问它的元素,向前和向后循环它们。

Which is the fastest access type between those two ? 这两者之间的访问类型最快?

Iterator access: 迭代器访问:

std::vector<SomeClass *> v;
std::vector<SomeClass *>::iterator i;
std::vector<SomeClass *>::reverse_iterator j;

// i loops forward, j loops backward
for( i = v.begin(), j = v.rbegin(); i != v.end() && j != v.rend(); i++, j++ ){
    // some operations on v items
}

Subscript access (by index) 下标访问(按索引)

std::vector<SomeClass *> v;
unsigned int i, j, size = v.size();

// i loops forward, j loops backward
for( i = 0, j = size - 1; i < size && j >= 0; i++, j-- ){
    // some operations on v items
}

And, does const_iterator offer a faster way to access vector elements in case I do not have to modify them? 而且,如果我不需要修改它们,const_iterator是否提供了访问向量元素的更快方法?

The performance difference is likely negligable or none (the compiler might optimise them to be identical); 性能差异可能是可忽略的或没有(编译器可能将它们优化为相同); you should worry about other things, like whether your program is correct (a slow but correct program is better than a fast and incorrect program). 你应该担心其他事情,比如你的程序是否正确(一个缓慢但正确的程序比快速和错误的程序更好)。 There are other advantages to using iterators though, such as being able to change the underlying container to one with no operator[] without modifying your loops. 使用迭代器还有其他优点,例如能够在没有修改循环的情况下将底层容器更改为没有operator[]容器。 See this question for more. 有关更多信息,请参阅此问

const_iterators will most likely have none, or negligable, performance difference compared to ordinary iterators. 与普通迭代器相比,const_iterators很可能没有或可忽略的性能差异。 They are designed to improve the correctness of your program by preventing modifying things that shouldn't be modified, not for performance. 它们旨在通过防止修改不应修改的内容而不是性能来提高程序的正确性。 The same goes for the const keyword in general. 一般来说, const关键字也是如此。

In short, optimisation should not be a concern of yours until two things have happened: 1) you have noticed it runs too slowly and 2) you have profiled the bottlenecks . 简而言之,在发生两件事情之前,优化不应该是您的关注:1)您注意到它运行得太慢而且2) 您已经描述了瓶颈 For 1), if it ran ten times slower than it could, but is only ever run once and takes 0.1ms, who cares? 对于1),如果它比它运行慢十倍,但只运行一次并需要0.1ms,谁在乎呢? For 2), make sure it's definitely the bottleneck, otherwise optimising it will have nearly no measurable effect on performance! 对于2),确保它绝对是瓶颈,否则优化它将对性能几乎没有可衡量的影响

A simple loop-based benchmark has been fulfilled. 已经实现了一个简单的基于循环的基准测试。 I used VS 2010 SP1 (release configuration). 我使用VS 2010 SP1(发布配置)。

  1. Use iterators (*it = *it + 1;) 使用迭代器(* it = * it + 1;)
  2. Use indices (vs[i] = vs[i] + 1;) 使用指数(vs [i] = vs [i] + 1;)

In several billions of iterations the second approach turned out to be a bit faster, by 1%. 在几十亿次迭代中,第二种方法变得更快,增加了1%。 The result (indices are slightly faster than iterators) is reproducible but the difference, as I said, is very small. 结果(索引比迭代器略快)是可重现的,但正如我所说,差异非常小。

If speed matters, then you should have time and will to run a profiler on it and see which works best in your case. 如果速度很重要,那么你应该有时间并且会在其上运行一个分析器,看看哪种情况最适合你的情况。

If it doesn't matter, then you are performing premature optimization and should STOP doing it. 如果没关系,那么你正在进行过早优化,应该停止这样做。

I had a test yesterday, use [] vs iterator, the code is create a vector with some elements and remove some elements from the vector. 昨天我进行了测试,使用[] vs迭代器,代码创建一个带有一些元素的向量,并从向量中删除一些元素。 This is the code uses operator [] to access elements 这是代码使用operator []来访问元素

  TimeSpent([](){
    std::vector<int> vt = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
    for (int i = int(vt.size()) - 1; i >= 0; i--)
    {
      if (vt[i] % 2 == 0)
      {
        //cout << "removing " << vt[i] << endl;
        vt.erase(vt.begin() + i);
      }
    }
  });

The following code is about access vector elements by using iterator 以下代码是通过使用迭代器来访问矢量元素

  TimeSpent([](){
    std::vector<int> vt = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
    for (std::vector<int>::iterator num = vt.begin(); num != vt.end();)
    {
      if (*num % 2 == 0)
      {
        num = vt.erase(num);
      }
      else
      {
        ++num;
      }
    }
  });

Tested by calling them by this function separately 通过此功能单独调用它们进行测试

void TimeSpent(std::function<void()> func)
{
  const int ONE_MIL = 10000;
  long times = ONE_MIL;
  std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
  while (times > 0)
  {
    func();
    --times;
  }
  std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
  cout << "time elapsed : " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << endl;
}


Tested environment is visual studio 2013 pro. 经过测试的环境是visual studio 2013 pro。 version 4.5.51650 版本4.5.51650
The results are : 结果是:
operator[] : 192 operator []:192
iterator : 212 迭代器:212
Summary: when we access the vector container, operator [] is faster than iterator. 简介:当我们访问向量容器时,operator []比迭代器更快。

I believe that vector iterators are implemented as pointers internally (in a good STL implementation), so in general there should be negligible performance difference between the two idioms. 我相信向量迭代器在内部实现为指针(在良好的STL实现中),因此通常两个习语之间的性能差异应该可以忽略不计。 But if you want to know how these perform on your platform, why don't you measure it with a little test program? 但是,如果您想知道这些在您的平台上表现如何,为什么不用一点测试程序来测量它? I don't think it would take more than 5 minutes to measure execution time of eg 1 million iterations with both variants... 我不认为用两种变体测量例如100万次迭代的执行时间需要花费超过5分钟...

通过优化(-O2),时间应该改善(应该几乎相同)。

As always, it depends. 一如既往,这取决于。 Normally I wouldn't think you'd see any kind of difference, but only you can determine that by profiling your code. 通常情况下,我不认为您会看到任何差异,但只有您可以通过分析您的代码来确定。 Some compilers implement vector iterators as raw pointers, and some don't. 有些编译器将矢量迭代器实现为原始指针,而有些编译器则不实现。 Also, in debug builds, some compilers may be using a checked iterator, which may be slower. 此外,在调试版本中,某些编译器可能正在使用已检查的迭代器,这可能会更慢。 But in production mode it may not be any different. 但在生产模式下,它可能没有任何不同。 Profile it and see. 简介并查看。

I was confused about something similar and wrote a program to test the performance : https://github.com/rajatkhanduja/Benchmarks/blob/master/C%2B%2B/vectorVsArray.cpp 我对类似的东西感到困惑,并编写了一个程序来测试性能: https//github.com/rajatkhanduja/Benchmarks/blob/master/C%2B%2B/vectorVsArray.cpp

Here's the relevant observations for reading/writing to vector<int> of size 1m using g++ (without any optimization flags), on Linux-i686 (64-bit machine) with 7.7 GB RAM:- 以下是在具有7.7 GB RAM的Linux-i686(64位机器)上使用g ++(没有任何优化标志)读取/写入大小为1m的vector <int>的相关观察结果: -

Time taken to write to vector using indices. 使用索引写入向量的时间。 : 11.3909 ms :11.3909毫秒

Time taken to read from vector using indices, sequentially. 按顺序使用索引从矢量读取的时间。 : 4.09106 ms :4.09106毫秒

Time taken to read from vector using indices, randomly. 使用索引从矢量中读取的时间,随机。 : 39 ms :39毫秒

Time taken to write to vector using iterators (sequentially). 使用迭代器(顺序)写入向量所花费的时间。 : 24.9949 ms :24.9949毫秒

Time taken to read from vector using iterators (sequentially). 使用迭代器从矢量读取所需的时间(顺序)。 : 18.8049 ms :18.8049毫秒

In terms of speed, I think might be almost same. 在速度方面,我认为可能几乎相同。 Better, you can profile and check anyway. 更好,无论如何你都可以进行剖析和检查。

At least you can reduce the number of variables used :) 至少你可以减少使用的变量数量:)

for( i = 0; i < size ; i++){
    // some operations on v items
    v[i];
    v[size-i+1];
}

About const_iterator : Pls refer my Q: A re const_iterators faster ? 关于const_iterator :请参考我的问: 更快的const_iterators?

I'd go for iterators, but what I would optimize is calling end() in the loop and would change preincrement to postincrement. 我会选择迭代器,但我要优化的是在循环中调用end()并将preincrement更改为postincrement。 Ie I'd 即我

std::vector<SomeClass *> v;
std::vector<SomeClass *>::iterator i,ie;
std::vector<SomeClass *>::reverse_iterator j,je;

// i loops forward, j loops backward
for( i=v.begin(),ie=v.end(), j=v.rbegin(),je=v.rend(); i!=ie && j!=je; ++i,++j ){
    // some operations on v items
}

And I don't think it's premature microoptimization, it's just writing better code. 我不认为这是过早的微观优化,它只是编写更好的代码。 Much less evil than calling every attempt to write efficient code premature microoptimization and substituting thinking with profiling. 比调用每一次尝试编写有效代码过早的微优化并用分析代替思考要少得多。

You are not only prematurely optimizing, you are micro-optimizing. 您不仅要过早地进行优化,还要进行微观优化。 This is an evil almost as bad as the former (the difference being that very, very, very rarely it is actually necessary to micro-optimize). 这是一种几乎与前者一样糟糕的邪恶(不同之处在于非常非常非常非常需要微观优化)。 Put the two together and you've got a recipe for disaster. 把两者放在一起,你就有了灾难的秘诀。

If you run a profiler and find this area of code is a bottleneck then you will need to optimize. 如果您运行探查器并发现此代码区域是瓶颈,那么您将需要进行优化。 You don't optimize by trying to reduce your loop from taking 23 clock cycles to 22. You optimize by finding ways to reduce the O() of your algorithm. 您不需要通过尝试将循环从23个时钟周期减少到22来进行优化。通过寻找减少算法的O()来优化。 But until you run a profiler you should be paying more attention to design than any other concern. 但是在你运行一个分析器之前,你应该更多地关注设计而不是任何其他问题。

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

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