繁体   English   中英

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

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

说,我有一个

std::vector<SomeClass *> v;

在我的代码中,我需要经常在程序中访问它的元素,向前和向后循环它们。

这两者之间的访问类型最快?

迭代器访问:

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
}

下标访问(按索引)

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
}

而且,如果我不需要修改它们,const_iterator是否提供了访问向量元素的更快方法?

性能差异可能是可忽略的或没有(编译器可能将它们优化为相同); 你应该担心其他事情,比如你的程序是否正确(一个缓慢但正确的程序比快速和错误的程序更好)。 使用迭代器还有其他优点,例如能够在没有修改循环的情况下将底层容器更改为没有operator[]容器。 有关更多信息,请参阅此问

与普通迭代器相比,const_iterators很可能没有或可忽略的性能差异。 它们旨在通过防止修改不应修改的内容而不是性能来提高程序的正确性。 一般来说, const关键字也是如此。

简而言之,在发生两件事情之前,优化不应该是您的关注:1)您注意到它运行得太慢而且2) 您已经描述了瓶颈 对于1),如果它比它运行慢十倍,但只运行一次并需要0.1ms,谁在乎呢? 对于2),确保它绝对是瓶颈,否则优化它将对性能几乎没有可衡量的影响

已经实现了一个简单的基于循环的基准测试。 我使用VS 2010 SP1(发布配置)。

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

在几十亿次迭代中,第二种方法变得更快,增加了1%。 结果(索引比迭代器略快)是可重现的,但正如我所说,差异非常小。

如果速度很重要,那么你应该有时间并且会在其上运行一个分析器,看看哪种情况最适合你的情况。

如果没关系,那么你正在进行过早优化,应该停止这样做。

昨天我进行了测试,使用[] vs迭代器,代码创建一个带有一些元素的向量,并从向量中删除一些元素。 这是代码使用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);
      }
    }
  });

以下代码是通过使用迭代器来访问矢量元素

  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;
      }
    }
  });

通过此功能单独调用它们进行测试

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;
}


经过测试的环境是visual studio 2013 pro。 版本4.5.51650
结果是:
operator []:192
迭代器:212
简介:当我们访问向量容器时,operator []比迭代器更快。

我相信向量迭代器在内部实现为指针(在良好的STL实现中),因此通常两个习语之间的性能差异应该可以忽略不计。 但是,如果您想知道这些在您的平台上表现如何,为什么不用一点测试程序来测量它? 我不认为用两种变体测量例如100万次迭代的执行时间需要花费超过5分钟...

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

一如既往,这取决于。 通常情况下,我不认为您会看到任何差异,但只有您可以通过分析您的代码来确定。 有些编译器将矢量迭代器实现为原始指针,而有些编译器则不实现。 此外,在调试版本中,某些编译器可能正在使用已检查的迭代器,这可能会更慢。 但在生产模式下,它可能没有任何不同。 简介并查看。

我对类似的东西感到困惑,并编写了一个程序来测试性能: https//github.com/rajatkhanduja/Benchmarks/blob/master/C%2B%2B/vectorVsArray.cpp

以下是在具有7.7 GB RAM的Linux-i686(64位机器)上使用g ++(没有任何优化标志)读取/写入大小为1m的vector <int>的相关观察结果: -

使用索引写入向量的时间。 :11.3909毫秒

按顺序使用索引从矢量读取的时间。 :4.09106毫秒

使用索引从矢量中读取的时间,随机。 :39毫秒

使用迭代器(顺序)写入向量所花费的时间。 :24.9949毫秒

使用迭代器从矢量读取所需的时间(顺序)。 :18.8049毫秒

在速度方面,我认为可能几乎相同。 更好,无论如何你都可以进行剖析和检查。

至少你可以减少使用的变量数量:)

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

关于const_iterator :请参考我的问: 更快的const_iterators?

我会选择迭代器,但我要优化的是在循环中调用end()并将preincrement更改为postincrement。 即我

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
}

我不认为这是过早的微观优化,它只是编写更好的代码。 比调用每一次尝试编写有效代码过早的微优化并用分析代替思考要少得多。

您不仅要过早地进行优化,还要进行微观优化。 这是一种几乎与前者一样糟糕的邪恶(不同之处在于非常非常非常非常需要微观优化)。 把两者放在一起,你就有了灾难的秘诀。

如果您运行探查器并发现此代码区域是瓶颈,那么您将需要进行优化。 您不需要通过尝试将循环从23个时钟周期减少到22来进行优化。通过寻找减少算法的O()来优化。 但是在你运行一个分析器之前,你应该更多地关注设计而不是任何其他问题。

暂无
暂无

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

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