2008-10-09 16 views
34

मैं विंडोज और मैक के बीच कुछ क्रॉस-प्लेटफ़ॉर्म कोड लिख रहा हूं।एसटीएल सूची के माध्यम से आप पीछे की तरफ कैसे जाते हैं?

यदि सूची :: अंत() "एक पुनरावर्तक लौटाता है जो किसी सूची में अंतिम तत्व को सफल करने वाले स्थान को संबोधित करता है" और किसी सूची को आगे बढ़ाने के दौरान चेक किया जा सकता है, पीछे की तरफ जाने का सबसे अच्छा तरीका क्या है?

इस कोड workson मैक लेकिन Windows पर नहीं (पहला तत्व परे घटती नहीं कर सकते हैं):

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

इस विंडोज पर काम करता है:

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

वहाँ एक और तरीका पिछड़े पार करने के लिए है कि है एक लूप में लागू किया जा सकता है?

+1

यह केवल कार्यान्वयन का दुर्घटना होगा कि आपका पहला उदाहरण (अंतराल() के मुकाबले सर्कुलर इटरेटर) काम करेगा। – Justsalt

उत्तर

60

पुनरावर्तक के बजाय रिवर्स_इटरेटर का उपयोग करें। शुरू करने के बजाय rbegin() & rend() का उपयोग करें() & अंत()।

एक और संभावना, यदि आप BOOST_FOREACH मैक्रो का उपयोग करना चाहते हैं तो बूस्ट 1.36.0 में प्रस्तुत BOOST_REVERSE_FOREACH मैक्रो का उपयोग करना है।

+0

इटरेटर और रिवर्स_इटरेटर के लिए प्रलेखन लगभग समान हैं। एक इटरेटर बिडरेक्शनल है तो अंतर क्या है? – AlanKley

+2

अंतर यह है कि आप अभी भी इटरेटर को बढ़ाने के लिए "++ Iter" करते हैं, बनाम "- Iter"। या मैं गलत हूँ? – steffenj

+0

नहीं, आप सही हैं जो पिछड़े जाने के लिए बढ़ने के लिए थोड़ा अजीब है लेकिन यह भी समझ में आता है। हालांकि रिवर्स_इटरेटर अनावश्यक लगता है कि इटरेटर बिडरेक्शनल है। रिवर्स_इटरेटर के लिए दस्तावेज़ कहते हैं कि यह एक उल्टा सूची पर कार्य करता है; निश्चित रूप से यह पहले सूची internaly विपरीत नहीं है। – AlanKley

13

शायद आप रिवर्स इटेटरेटर्स चाहते हैं। स्मृति से:

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

धन्यवाद कि अच्छा लगता है। लेकिन यह भी एक विशेष रिवर्स_इटरेटर बनाने के लिए अपशिष्ट लगता है जब इटेटरेटर द्वि-दिशात्मक – AlanKley

+0

होने का अनुमान लगाया जाता है, यह "...> :: reverse_iterator iter = ..." – steffenj

+0

@AlanKley मुझे लगता है कि लूप के लिए आपने जो रखा है आपका सवाल ठीक है। कारण यह है कि मुझे लगता है कि यह काम करता है क्योंकि .end() सदस्य फ़ंक्शन एक सेंटीनेल मान देता है जिसे अंतिम तत्व से अगले सूचक का मान और पहले तत्व पर पिछला पॉइंटर भी दिया जाता है। –

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 का उपयोग करने के लिए।

हालांकि, मैं यह उल्लेख करना चाहता था कि रिवर्स इटरेटर्स को "वर्तमान" पुनरावर्तक स्थिति को एक-एक करके (मानक पुस्तकालय के जीएनयू कार्यान्वयन पर) को लागू करने के लिए लागू किया गया है।

इस श्रृंखला के लिए रिवर्स में एक सीमा के आगे के रूप में ही अर्थ विज्ञान के लिए [शुरू, अंत) कार्यान्वयन को आसान बनाने के लिए किया जाता है, ताकि और [rbegin, उखड़ना)

इसका मतलब क्या है कि एक अपसंदर्भन है इटरेटर एक नया अस्थायी बनाने शामिल है, और उसके बाद हर बार यह decrementing, :

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

इस प्रकार, एक reverse_iterator अपसंदर्भन एक सामान्य इटरेटर की तुलना में धीमी है।

हालांकि, इसके बजाय आप अपने आप को यात्रा रिवर्स अनुकरण करने के लिए नियमित रूप से द्विदिश iterators उपयोग कर सकते हैं, इस भूमि के ऊपर से परहेज:

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

परीक्षण इस समाधान से पता चला है ~ 5 गुना तेजी से प्रत्येक भिन्नता में इस्तेमाल के लिए होने के लिए लूप का शरीर।

नोट: उपरोक्त कोड के साथ परीक्षण नहीं किया गया था, क्योंकि std :: cout बाधा बन गई होगी।

यह भी ध्यान दें: 'दीवार घड़ी का समय' अंतर ~ 5 सेकंड था जिसमें 10 मिलियन तत्वों की एक std :: सूची आकार था। तो, वास्तव में, जब तक कि आपके डेटा का आकार इतना बड़ा न हो, बस rbegin() rend() को चिपकाएं!

+0

इसे फिर से देख रहे हैं, शायद आप केवल वर्तमान = --end() के साथ प्रारंभ करना चाहते हैं; और लूप के अंदर वृद्धि चरण छोड़ दें। यह रिक्त सरणी के खिलाफ भी सुरक्षा करेगा जो ऊपर मेरा संस्करण नहीं है। जब से मैंने परीक्षण नहीं किया है, तब से मैं मूल पोस्ट को छोड़ दूंगा। – mmocny

+0

मुझे नहीं लगता कि यह तब तक काम करेगा जब तक आप अपनी लूप स्थिति भी बदल नहीं लेते। अन्यथा आप पहली वस्तु गायब हो जाएंगे (यदि वर्तमान == प्रारंभ() ' – Griddo

+0

लूप के लिए पहली पंक्ति एक कमी करता है, तो हां, मुझे लगता है कि लूप का निष्पादन नहीं होगा। कोशिश करने के लिए बस एक त्वरित परीक्षण लिखें! वैसे भी, मुझे नहीं लगता कि यह इस मुहावरे का उपयोग करने का सबसे अच्छा तरीका है, और कुछ हालिया परीक्षणों में मैंने भाग लिया है ताकि पूर्ण अनुकूलन के तहत इसे पुनरावृत्त करने के लिए एक स्पष्ट गति सुधार नहीं दिखाया जा सके। हालांकि, यह अभी भी ध्यान देने योग्य है कि हुड के तहत क्या हो रहा है और तदनुसार परीक्षण! – mmocny