2008-10-09 54 views
34

我在Windows和Mac之間編寫了一些跨平臺的代碼。你如何通過STL列表向後迭代?

如果list :: end()「返回一個迭代器來處理列表中最後一個元素的後續位置」並且可以在向前遍歷列表時檢查,那麼向後遍歷的最佳方法是什麼?

此代碼workson在Mac而不是Windows上(不能超過遞減第一要素):

list<DVFGfxObj*>::iterator iter = m_Objs.end(); 
for (iter--; iter!=m_Objs.end(); iter--)// By accident discovered that the iterator is circular ? 
{ 
} 

這適用於Windows:

list<DVFGfxObj*>::iterator iter = m_Objs.end(); 
    do{ 
     iter--; 
    } while (*iter != *m_Objs.begin()); 

有另一種方式來遍歷落後是可以在for循環中實現?

+1

這隻會是一個實現的意外,你的第一個例子(循環迭代器,比較end())將工作。 – Justsalt 2008-10-09 20:23:53

回答

60

使用reverse_iterator代替迭代器。 使用rbegin()& rend()而不是begin()& end()。

另一種可能性,如果您喜歡使用BOOST_FOREACH宏,則使用Boost 1.36.0中引入的BOOST_REVERSE_FOREACH宏。

+0

iterator和reverse_iterator的文檔幾乎相同。迭代器是雙向的,所以diff是什麼? – AlanKley 2008-10-09 20:00:46

+2

區別在於你仍然在執行「++ Iter」來增加迭代器,而不是「--Iter」。還是我錯了? – steffenj 2008-10-09 20:03:30

+0

不,你說得對,這是有點奇怪的增量倒退,但也有道理。雖然reverse_iterator似乎沒有必要,因爲迭代器是雙向的。 reverse_iterator的文檔表示它在一個反向列表上起作用;它肯定不會首先顛倒內部。 – AlanKley 2008-10-09 20:08:38

13

你可能想要反向迭代器。從內存:

list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin(); 
for(; iter != m_Objs.rend(); ++iter) 
{ 
} 
4

由於已經由費魯吉歐,使用reverse_iterator的提到:

for (std::list<int>::reverse_iterator i = s.rbegin(); i != s.rend(); ++i) 
5

這應該工作:

list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin(); 
for (; iter!= m_Objs.rend(); iter++) 
{ 
} 
16

最好/最簡單的方法來扭轉迭代一名單(如已經聲明)使用反向迭代器rbegin/rend。

不過,我想提一提,反向迭代器實現存儲「當前」迭代器位置的off-by-一個(GNU的執行標準庫中至少)。

這樣做是爲了簡化實現,以使範圍中反向爲具有相同的語義的範圍內向前[開始,結束)和[rbegin,分割)

這意思是,訪問一個迭代涉及創建一個新的臨時,然後每一次遞減它,

reference 
    operator*() const 
    { 
_Iterator __tmp = current; 
return *--__tmp; 
    } 

因此,解引用reverse_iterator的是比正常迭代慢。

然而,你可以改用常規的雙向迭代器來模擬反向迭代自己,避免這種開銷:

for (iterator current = end() ; current != begin() ; /* Do nothing */) 
{ 
    --current; // Unfortunately, you now need this here 
    /* Do work */ 
    cout << *current << endl; 
} 

測試表明該解決方案是在使用的每個解引用更快〜5倍循環體。

注:測試不是用上面的代碼完成,爲性病::法院本來的瓶頸。

另請注意:'掛鐘時間'差異爲5秒,std :: list大小爲1000萬個元素。所以,實際上,除非你的數據量很大,只要堅持rbegin()rend()!