2013-02-07 9 views
8

एक्सकोड 4.6 का उपयोग कर मैक ओएस एक्स पर परीक्षण किया गया।किसी सूची के _first_ तत्व को हटाने से `.rend()` को अमान्य क्यों किया जाता है?

इस उदाहरण कोड एक std::list कार्यों के अंतिम तत्व को हटाने से पता चलता के रूप में मैं उम्मीद: list::end() के लिए एक इटरेटर संदर्भ अभी भी "अंत अतीत 1" और अभी भी मान्य है, भी पिछले तत्व को हटाने के माध्यम से।

लेकिन दूसरा उदाहरण काउंटर मेरे अंतर्ज्ञान। सूची में list::rend() बदलता है, जिसे मैंने सोचा था कि "शुरुआत से पहले 1" था।

क्या मेरी उम्मीद गलत थी? यह गलत क्यों था? अंतिम तत्व को हटाने के माध्यम से "1 अतीत के अंत" का आपका संदर्भ वैध क्यों है (क्या यह नहीं होना चाहिए?), लेकिन ") के सामने" 1 () सामने के तत्व को हटाने के बाद अमान्य हो जाता है?

void printList(list<int>& os) 
{ 
    for(int& i : os) 
    printf("%d ", i) ; 
    puts(""); 
} 

void testList() 
{ 
    list<int> os ; 
    os.push_back(1) ; 
    os.push_back(2) ; 
    os.push_back(3) ; 
    os.push_back(4) ; 
    os.push_back(5) ; 

    // Forward iterators: reference to .end() not invalidated when remove last elt. 
    list<int>::iterator fwdEnd = os.end() ; 
    printList(os) ; 
    os.erase(--os.end()) ; // remove the 5 (last elt) 
    printList(os) ; 
    if(fwdEnd == os.end()) puts("YES, fwdEnd==os.end() still, iterators not invalidated") ; // I get __this__ result 
    else puts("NO: fwdEnd INVALIDATED") ; 



    list<int>::reverse_iterator revEnd = os.rend() ; 
    // remove the front element 
    printList(os) ; 
    os.erase(os.begin()) ; // removes the 1 
    printList(os) ; 
    if(revEnd == os.rend()) puts("YES revEnd is still valid") ; 
    else puts("NO: revEnd NOT valid") ; // I get __this__ result 
} 
+0

जिस तरह से मैं इसे समझता हूं, एक रिवर्स इटेटरेटर यह इंगित करता है कि यह क्या प्रतीत होता है। एक "शुरुआत से पहले एक" रिवर्स इटेटरेटर एक सामान्य इंटरैटर को लपेटता है जो शुरुआत को संदर्भित करता है। जब लपेटा हुआ इटरेटर अमान्य हो जाता है, तो रिवर्स इटरेटर भी होता है। लेकिन मेरे पास इस बात को वापस करने के लिए मानक से उद्धरण नहीं है। – hvd

+0

मुझे लगता है कि दूसरा प्रश्न होगा: * "क्या 'rbegin' पहले उदाहरण में समान रूप से अमान्य है?" * – user7116

उत्तर

16

इस तथ्य को एक रिवर्स इटरेटर एक नियमित इटरेटर से कुछ भिन्न संदर्भित तर्क है कि की वजह से है:। यह एक तत्व की ओर इशारा करता है, लेकिन जब dereferenced, यह पिछले तत्व के लिए संदर्भ पैदावार

यदि आप निम्न का प्रयास करते हैं तो आप आसानी से इसे देखेंगे:

#include <vector> 
#include <iostream> 
#include <algorithm> 

using namespace std; 

int main() 
{ 
    vector<int> v = { 1, 2, 3, 4, 5, 6 }; 
    auto i = find(begin(v), end(v), 3); 
    cout << *i << endl; 

    vector<int>::const_reverse_iterator ri(i); 
    cout << *ri << endl; 
} 

उत्पादन किया जाना चाहिए:

3 
2 

जब एक रिवर्स इटरेटर एक निश्चित तत्व के लिए शारीरिक रूप से अंक, यह तत्व है जो इससे पहले आने के लिए तार्किक अंक। इस प्रकार, एक रिवर्स इटरेटर शारीरिक रूप से तत्व करने के लिए एक संग्रह में सूचकांक i, जब dereferenced, पैदावार (के लिए एक संदर्भ) तत्व के साथ सूचकांक i-1 साथ ओर इशारा करते हुए:

     i, *i 
         | 
    -  1  2  3  4  5  6  - 
       |  | 
       *ri ri 

यह कारण है कि rend() वास्तव में से एक इटरेटर वापसी संग्रह में पहले तत्व को इंगित करता है, न कि पहले तत्व से पहले। इसलिए, पहले तत्व को हटाने से, इसे अमान्य कर दिया जाता है।

  begin, *begin      end, *end 
      |         | 
    -  1  2  3  4  5  6  - 
    |  |        |  | 
*rend  rend     *rbegin  rbegin 

यह केवल सूचियों पर लागू नहीं होता है, लेकिन सभी संग्रह जो बिडरेक्शनल इटरेटर्स प्रदान करते हैं।

+2

ग्रेट आरेख! – StilesCrisis

+0

@StilesCrisis: धन्यवाद :-) –

+0

तो _ "शुरुआत के सामने 1" नामक कोई वास्तविक तत्व नहीं है .. जबकि एक आगे इटरेटर वास्तव में "अंत से पहले 1" को इंगित करता है, एक रिवर्स इटेटरेटर केवल शुरुआत को इंगित करता है, और जब संदर्भित किया गया है, तो "शुरुआत के सामने 1" को इंगित करता है – bobobobo