2008-10-13 10 views
6

मेरे पास एक पुरानी प्रोजेक्ट है जिसे विजुअल स्टूडियो 2003 का उपयोग करके बनाया गया था और मैंने इसे हाल ही में बनाम2005 के साथ पुनः संयोजित किया। हालांकि, रनटाइम के दौरान, मैं निम्नलिखित त्रुटि मिलती है:सूची इटेटरेटर वृद्धिशील नहीं

सूची इटरेटर नहीं incrementable

मैं इस समारोह के लिए कार्यक्रम का पता लगाया:

void InputQueue::update() 
{ 
    list<PCB>::iterator iter; 
    list<PCB>::iterator iterTemp; 
    for(iter = begin(); iter != end(); iter++) 
    { 
     if(iter->arrivalTime == 0) 
     {   
      ReadyQueue::getInstance()->add(*iter); 
      iterTemp = iter; 
      iter++; 
      erase(iterTemp); 
     } 
    } 
} 

मैं एक सी ++ विशेषज्ञ नहीं हूँ और यह जहाँ तक है क्योंकि वीएस डीबगर ने मुझे मिला। क्या कोई मुझे समझा सकता है कि समस्या क्या है?

धन्यवाद

उत्तर

9

सूचना है कि अगर iter->arrivalTime == 0, तो सूची इटरेटर दो बार वृद्धि हो जाता है: पाश के अंत में एक बार तत्व हटाने से पहले, और एक बार फिर से।

यदि आइटम को हटाया जाना है तो सूची में अंतिम आइटम है, यह स्पष्ट रूप से सही ढंग से काम नहीं करेगा। मुझे लगता है कि यह कभी भी VS2003 में सही ढंग से काम नहीं करता है, लेकिन वीएस2005 आपको इसके बारे में बेहतर अलर्ट करता है। :-)

याद रखें, यह पिछले end() को पुन: स्थापित करने के लिए अपरिभाषित व्यवहार है। बिल्कुल कुछ भी हो सकता है, जैसे प्रोग्राम क्रैश, या (इस मामले में) एक त्रुटि संदेश।

1

मैं सिर्फ अपने कोड की कुछ लाइनें दिखाने के लिए जहां समस्या है छिपाना लिए जा रहा हूँ:

for(iter = begin(); iter != end(); iter++) // *** 
    { 
     if(iter->arrivalTime == 0) 
     {      

       iter++; // *** 

     } 
    } 

दो पंक्तियों में चिह्नित ***, आप iterator incrementing कर रहे हैं। समस्या यह है कि दो पंक्तियों में से दूसरे पर, आप यह देखने की जांच नहीं कर रहे हैं कि आप कंटेनर के अंत तक नहीं गए हैं। प्रभावी रूप से, यदि आप आंतरिक पाश में आते हैं, तो आप दो बार बढ़ रहे हैं, लेकिन केवल जांच कर रहे हैं कि आप एक बार बढ़ने में सक्षम हैं या नहीं।

एक समाधान दूसरी वेतन वृद्धि करने से पहले जाँच करने के लिए है कि क्या आप end() पर हो रहा है, लेकिन जैसे आप (एक नक्शे के एक ही आपरेशन पहिले से करने के रूप में मैं my question a while ago में था एक कंटेनर से छानने आइटम के साथ क्या करने की कोशिश कर रहे हैं यह मेरे लिए लग रहा है उस मामले में, लेकिन यह ज्यादातर एसटीएल कंटेनर के लिए लागू होता है)।

0

मुझे विश्वास है कि क्रिस सही है। हालांकि, एक और समस्या इस तथ्य से हो सकती है कि आप इसे पुनरावर्तक को असाइन करते हैं। - क्या सूची इटरेटर को असाइन करने योग्य होने की गारंटी है? मानक को देखे बिना, मुझे ऐसा नहीं लगता है क्योंकि एसईआईआई दस्तावेजों के एसजीआई दस्तावेज में असाइनमेंटिटी का उल्लेख कहीं नहीं किया गया है।

+0

ऐसा लगता है कि http://www.sgi.com/tech/stl/Iterators.html यह है कि इटरेटर अग्रेषित करने योग्य हैं। std :: सूची के इटरेटर्स बिडरेक्शनल इटरेटर्स (http://www.sgi.com/tech/stl/List.html, http://www.sgi.com/tech/stl/ReversibleContainer.html) हैं, और इस प्रकार भी हैं आगे इटरेटर्स। :-) –

+0

हम्म, क्या इसका मतलब है "बहु-पास"? क्योंकि अन्यथा इटरेटर * के असाइनमेंट * के बारे में कुछ भी नहीं कहा जाता है (जैसा कि इसके मूल्य के विपरीत है!)। –

14

मैं अपने पाश फिर से लिखते थे निम्नलिखित की तरह बनना:

while (iter != end()) 
{ 
    if (iter->arrivalTime == 0) 
    { 
    ReadyQueue::getInstance()->add(*iter); 
    iter = erase(iter); 
    } 
    else 
    { 
    ++iter; 
    } 
} 

अब आप सही ढंग से सूची हर सूचकांक जाँच के माध्यम से पाशन कर रहे हैं।

+0

यदि आप –

+1

I am - iter = erase (iter) के पहले भाग में इटेटरेटर को बढ़ा नहीं रहे हैं। मिटाए गए फ़ंक्शन को हटाए जाने वाले एक के बाद नया पुनरावर्तक लौटाता है। –

+0

ओह ठीक मुझे कभी याद मत करो। यह कुछ प्रकार के कंटेनरों के साथ काम नहीं करता है, आपको लगता है कि –

0

यह एक साइडेनोट है, लेकिन एक महत्वपूर्ण है।

मुझे लगता है कि आप std::ist<PCB> से प्राप्त करते हैं। मुझे कहना होगा: कार्यक्षमता का पुन: उपयोग करने के लिए विरासत में अक्सर मेरे लिए अच्छा नहीं रहा है। लेकिन चूंकि आप इस परियोजना को 'विरासत' भी दे रहे हैं, इसके बारे में कुछ भी करने के लिए कुछ भी नहीं है ...

+0

कार्यान्वयन विरासत, जबकि आदर्श नहीं, माफ कर सकते हैं यदि यह केवल निजी विरासत है। :-) –

0

यदि आपको "इटेटरेटर असंगत सूची" मिल रही है तो शायद यह संभव है क्योंकि आपके "ReadyQueue :: getInstance() -> जोड़ें (* आईटीईआर); " आप * इटर में कुछ बदल रहे हैं जो हैश एल्गोरिदम डालने के दौरान किए गए मिटाने के लिए एक अलग मान देता है।

0

क्या मैं एक सरल एल्गोरिदम सुझा सकता हूं?

नि: शुल्क फ़ंक्शन std::remove_if का उपयोग आपकी सूची को 2 में विभाजित करने के लिए किया जा सकता है, जो तत्व मिलान करते हैं या भविष्य से मेल नहीं खाते हैं (यानी आगमन समय == 0)। यह रेंजों को अलग करने वाले इटरेटर को लौटाता है। फिर आप ReadyQueue::getInstance()->add(subrange_begin, subrange_end)पर कॉल कर सकते हैं (आपके पास वह अधिभार है, है ना?) और बाद में सब्रेंज मिटाएं।

बस एक मामला जहां आप अपने स्वयं के लूप लिखने के बजाय एसटीएल एल्गोरिदम का उपयोग कर सकते हैं।

1

मूल कारण "list.erase()" इटरेटर बदल देगा। "के लिए" पाश के लिए सही लिखने:

for (list<CMessage*>::iterator it=que.begin(); it!=que.end(); ++it) 
    { 
    if(m_type == (*it)->m_type) 
    { 
     delete *it; 
     it=que.erase(it); //"list.erase()" will change the iterator!!! 
     if(it==que.end()) break; //Check again!!! 
     //still has side effect here. --it? 
    } 
    } 

लेकिन यह अभी भी पक्ष प्रभाव है, इसलिए मार्क जबकि समाधान सबसे अच्छा हो जाएगा।

संबंधित मुद्दे