2009-05-26 8 views
21

push_back या push_front एक डेक के इटरेटर को अमान्य क्यों करता है? शीर्षक के रूप में

एक डेक की मेरी समझ यह थी कि इसे "ब्लॉक" आवंटित किया गया था। मैं नहीं देखता कि अधिक जगह आवंटित करने से इटरेटर्स को अमान्य कर दिया जाता है, और यदि कुछ भी हो, तो कोई ऐसा सोचता है कि एक डेक के इटरेटर को वेक्टर की तुलना में अधिक गारंटी होगी, कम नहीं।

+5

आईआईआरसी, जीसीसी के डेक के कार्यान्वयन ने उन ब्लॉकों को पॉइंटर्स की एक सरणी रखी है ... यदि सरणी को फिर से आवंटित करने की आवश्यकता है, तो इटरेटर अवैध हो सकते हैं। शायद यही कारण है? मुझे यकीन नहीं है ... कम से कम बताता है कि क्यों समाप्त होने के लिए प्रविष्टियां इटरेटर्स को अमान्य करती हैं, लेकिन तत्वों के संदर्भ/पॉइंटर्स नहीं। –

उत्तर

16

सी ++ मानक निर्दिष्ट नहीं करता है कि डेक कैसे कार्यान्वित किया जाता है। नए हिस्से को आवंटित करके इसे पिछले स्थान पर आवंटित करने के लिए नई जगह आवंटित करने की आवश्यकता नहीं है, यह आवश्यक है कि प्रत्येक छोर पर सम्मिलन निरंतर समय को आवंटित किया जाए।

तो, डेक को कार्यान्वित करने के तरीके को देखना आसान है, जैसे कि यह गारंटी देता है [*], यह ऐसा करने का एकमात्र तरीका नहीं है।

[*] इटरेटर्स के पास एक तत्व का संदर्भ है, साथ ही ब्लॉक के संदर्भ में यह संदर्भ है ताकि वे ब्लॉक के सिरों को आगे बढ़कर आगे बढ़ सकें। इसके अलावा मुझे लगता है कि डेक के संदर्भ में, operator+ यादृच्छिक-पहुंच इटरेटर्स के लिए अपेक्षित समय के रूप में निरंतर समय हो सकता है - ब्लॉक से ब्लॉक तक लिंक की एक श्रृंखला के बाद पर्याप्त नहीं है।

+4

डेक सूची नहीं है, ब्लॉक जंजीर नहीं हैं! – curiousguy

2

जब भी आप भाग में आवंटित होते हैं, तब भी एक सम्मिलित होने पर उस विशेष खंड को फिर से स्थानांतरित किया जाएगा यदि पर्याप्त जगह नहीं है (जैसा वैक्टर के साथ मामला है)।

+0

पुनर्वितरण यहां कुंजी है। – curiousguy

5

मुख्य बात यह है कि किसी भी धारणा को केवल इटरेटर के साथ नहीं माना जाता है जैसे कि इसे अमान्य कर दिया जाएगा।

भले ही यह ठीक काम करता है, फिर भी एक अलग मंच के लिए कंपाइलर या कंपाइलर का बाद का संस्करण साथ आ सकता है और आपका कोड तोड़ सकता है। वैकल्पिक रूप से, एक सहयोगी साथ आ सकता है और अपने डेक को वेक्टर या लिंक्ड सूची में बदलने का फैसला कर सकता है।

13

अधिक रूचिकर है कि push_back और push_frontनहीं एक Deque के तत्वों के लिए किसी भी संदर्भ अमान्य हो जाएगी है। केवल इटेटर को अमान्य माना जाना चाहिए।

मानक, मेरे ज्ञान के लिए, यह क्यों नहीं बताता है। हालांकि अगर एक पुनरावर्तक को कार्यान्वित किया गया था जो कि उसके तत्काल पड़ोसियों से अवगत था - एक सूची है - कि इटेटरेटर अमान्य हो जाएगा अगर यह उस तत्व को इंगित करता है जो डेक के किनारे और ब्लॉक के किनारे दोनों था।

+5

मुझे लगता है कि एक और कारण यह है कि एक तत्व की अनुक्रमणिका को रखकर इटरेटर लागू किया जा सकता है। यदि डेक के प्रारंभ/अंत में कुछ डाला जाता है, तो यह सूचकांक अब और वैध नहीं है (हालांकि, एक-एक-एक), हालांकि उस तत्व के किसी भी सूचक/संदर्भ को इंगित करना अभी भी वैध है, क्योंकि कोई पुनर्वितरण नहीं हुआ है, पाठ्यक्रम)। वही जब हम ब्लॉक-पॉइंटर्स की एक सरणी में इंडेक्स में रहते हैं (जैसा कि मैंने प्रश्न पर मेरी टिप्पणी में अनुमान लगाया है)। –

+0

सीधा कार्यान्वयन के आधार पर इसके बारे में एक स्पष्टीकरण के लिए मेरा [उत्तर] (http://stackoverflow.com/a/39420347/3903076) देखें। – filipos

0

क्योंकि मानक कहता है कि यह कर सकता है। यह जरूरी नहीं है कि डेक को टुकड़ों की सूची के रूप में लागू किया जाए। यह विशेष पूर्व और पोस्ट की स्थितियों और विशेष एल्गोरिदमिक जटिलता न्यूनतम के साथ एक विशेष इंटरफ़ेस को अनिवार्य करता है।

कार्यान्वयनकर्ता जो कुछ भी चुनते हैं, उन्हें लागू करने के लिए स्वतंत्र हैं, जब तक कि यह उन सभी आवश्यकताओं को पूरा करता है। एक समझदार कार्यान्वयन भाग की सूचियों का उपयोग कर सकता है, या यह विभिन्न व्यापार-बंद के साथ किसी अन्य तकनीक का उपयोग कर सकता है।

यह कहना असंभव है कि एक तकनीक सभी परिस्थितियों में सभी उपयोगकर्ताओं के लिए सख्ती से बेहतर है। यही कारण है कि मानक कार्यान्वयन करने वालों को कुछ स्वतंत्रता चुनने देता है।

+0

मुझे नहीं लगता कि आप का मतलब है कि आप एक सूची (उदाहरण के लिए, std :: सूची) का हिस्सा हैं, तब यादृच्छिक-पहुंच इटरेटर ओ (1) नहीं हो सकते हैं। –

+1

एक कार्यान्वयन पर एक सरसरी नज़र से पता चलता है कि एक डेक एक std :: vector > जैसा है, जहां आंतरिक वेक्टर निश्चित रूप से आरक्षित है और कभी नहीं बढ़ता है; हालांकि यह बिल्कुल सही नहीं है, क्योंकि एक वेक्टर से pop_front तत्वों को स्थानांतरित करेगा। हालांकि, एक डेक :: इटेटरेटर वास्तव में इटरेटर की एक जोड़ी होगी। आंतरिक इटरेटर कभी भी अमान्य नहीं होता है (इसलिए क्यों संदर्भ अभी भी मान्य हैं), लेकिन बाहरी कंटेनर फिर से स्थानांतरित होने पर बाहरी व्यक्ति खराब हो सकता है। तो, कुछ ++ इटर के बाद, आप आंतरिक खंड के अंत को क्रॉल कर सकते हैं और बाहरी इटरेटर के माध्यम से अगले खंड में रीसेट करना होगा, और बूम। –

6

मेरा अनुमान है। push_back/push_front एक नया मेमोरी ब्लॉक आवंटित कर सकता है। एक डेक इटरेटर को पता होना चाहिए कि वृद्धि/कमी ऑपरेटर को अगले ब्लॉक में कूदना चाहिए। कार्यान्वयन उस जानकारी को इटेटरेटर में ही स्टोर कर सकता है। पुश_बैक/पुश_फ्रंट के बाद पुराने पुराने पुनरावर्तक को बढ़ाने/घटाने के उद्देश्य से काम नहीं कर सकता है।

यह कोड रन टाइम त्रुटि के साथ विफल हो सकता है या नहीं। मेरे विजुअल स्टूडियो पर यह डीबग मोड में विफल रहा लेकिन रिलीज मोड में निष्कर्ष पर चला गया। लिनक्स पर यह सेगमेंटेशन गलती हुई।

#include <iostream> 
#include <deque> 

int main() { 
    std::deque<int> x(1), y(1); 
    std::deque<int>::iterator iterx = x.begin(); 
    std::deque<int>::iterator itery = y.begin(); 

    for (int i=1; i<1000000; ++i) { 
     x.push_back(i); 
     y.push_back(i); 
     ++iterx; 
     ++itery; 
     if(*iterx != *itery) { 
      std::cout << "increment failed at " << i << '\n'; 
      break; 
     } 
    } 
} 
2

एक पुनरावर्तक डेटा का संदर्भ नहीं है। यह जानना चाहिए कि कैसे वृद्धि करना है, आदि

यादृच्छिक अभिगम का समर्थन करने के लिए, कार्यान्वयन में भाग के लिए पॉइंटर्स की गतिशील सरणी होगी। डेक इटरेटर इस गतिशील सरणी में इंगित करेगा। जब डेक बढ़ता है, तो एक नया हिस्सा आवंटित करने की आवश्यकता हो सकती है। गतिशील सरणी बढ़ेगी, इसके इटरेटर को अमान्य कर देगा और इसके परिणामस्वरूप, डेक के इटरेटर।

तो ऐसा नहीं है कि भाग को फिर से आवंटित किया गया है, लेकिन इन हिस्सों के पॉइंटर्स की सरणी हो सकती है। दरअसल, जोहान्स शैब ने नोट किया, संदर्भों को अवैध नहीं किया गया है।

यह भी ध्यान दें कि डेक की इटरेटर गारंटी वेक्टर की तुलना में कम नहीं है, जो कंटेनर बढ़ने पर भी अमान्य होती है।

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