2012-04-10 15 views
19

根據我發現的一些STL文檔,插入或刪除std :: list中的元素不會使迭代器失效。這意味着它可以遍歷列表(從begin()end()),然後使用push_front添加元素。例如,在下面的代碼中,我用元素a,b和c初始化一個列表,然後遍歷它並執行元素的push_front。結果應該是cbaabc,這正是我得到:爲什麼std :: list上的push_back會改變一個用rbegin初始化的反向迭代器?

std::list<std::string> testList; 
testList.push_back("a"); 
testList.push_back("b"); 
testList.push_back("c"); 

for (std::list<std::string>::iterator itList = testList.begin(); itList != testList.end(); ++itList) 
    testList.push_front(*itList); 

for (std::list<std::string>::const_iterator itList = testList.begin(); itList != testList.end(); ++itList) 
    std::cout << *itList << std::endl; 

當我使用反向迭代器(循環從rbegin()rend())和使用的push_back,我希望類似的行爲,即ABCCBA的結果。不過,我得到了不同的結果:

std::list<std::string> testList; 
testList.push_back("a"); 
testList.push_back("b"); 
testList.push_back("c"); 

for (std::list<std::string>::reverse_iterator itList = testList.rbegin(); itList != testList.rend(); ++itList) 
    testList.push_back(*itList); 

for (std::list<std::string>::const_iterator itList = testList.begin(); itList != testList.end(); ++itList) 
    std::cout << *itList << std::endl; 

結果不abccba,但abcccba。這是正確的,還有一個額外的C添加。

看起來第一個push_back也改變了用rbegin()初始化的迭代器的值。在push_back之後,它不再指向列表中的第3個元素(之前是最後一個元素),而是指向第4個元素(現在是最後一個元素)。

我用Visual Studio 2010和GCC測試了這個,並且都返回了相同的結果。

這是錯誤?或者我不知道的反向迭代器的一些奇怪的行爲?

回答

15

標準說,迭代器和引用插入過程中保持有效的反向通過。它沒有說任何有關反向迭代器的東西。 :-)

reverse_iterator返回的rbegin()內部保存值爲end()。經過push_back()這個值顯然不會像以前那樣。我不認爲標準說明它應該是什麼。顯而易見的選擇包括列表的前一個元素,或者如果它是固定值(如哨點節點),則停留在最後。


技術細節:由rend()返回的值不能begin()前點,因爲那是無效的。所以決定rend()應該包含begin()的值,並且所有其他反向迭代器將被進一步移位一個位置。 operator*彌補了這一點,並無論如何訪問正確的元素。

的24.5.1反向迭代器第一段表示:

類模板reverse_iterator的是,從該序列的結束迭代由其下方的迭代器定義 該序列的開始處的迭代器適配器。迭代器與其對應迭代器i之間的基本關係由以下標識建立:
&*(reverse_iterator(i)) == &*(i - 1)

+0

謝謝,你有沒有參考技術細節? – Patrick 2012-04-10 09:25:44

+1

添加了標準報價。 – 2012-04-10 09:34:11

+0

+1。我認爲這個標準引用了它。 – 2012-04-10 09:56:07

0

嘗試對兩者都使用迭代器。嘗試:

std::list<std::string>::iterator i = testList.end(); 

與--i

+0

我不在尋找替代解決方案。我想知道爲什麼反向迭代器突然指向其他內容,因爲這似乎與文檔相矛盾(請參閱http://www.sgi.com/tech/stl/List.html)。 – Patrick 2012-04-10 09:05:26

7

我想明白這一點,最好通過重新鑄造for環路作爲while循環開始:

typedef std::list<std::string> container; 

container testList; 
testList.push_back("a"); 
testList.push_back("b"); 
testList.push_back("c"); 

container::reverse_iterator itList = testList.rbegin(); 
while (itList != testList.rend()) { 
    testList.push_back(*itList); 
    ++itList; 
} 

伴隨着這一點,我們必須瞭解如何在一般reverse_iterator作品。具體來說,reverse_iterator確實指向之後的元素,這是您解除引用時得到的元素。 end()產生一個迭代器到容器的末尾 - 但對於像數組這樣的事物,沒有定義的方法指向容器的開始之前。 C++所做的是讓迭代器在結束之後開始,並且進展到開始,但是當您取消引用時,您會在之前得到其實際指向的元素

這實際上意味着你的代碼是這樣的:

enter image description here

之後,你幾乎你所期望的,推背B,然後A,所以你最終ABCCCBA。

+0

您是否可以指向規範或甚至參考站點,指出reverse_iterators以這種方式工作? (如果沒有,這不會使解釋錯誤必然,但如果沒有錯誤,這是一個執行錯誤) – immibis 2016-10-28 04:31:26

+0

@immibis:§[reverse.iterators]/1:「反向迭代器和其對應的迭代器之間的基本關係我通過身份建立:&*(reverse_iterator(i))==&*(i - 1)。「 – 2016-10-28 04:58:30

相關問題