簡體   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