2013-07-27 7 views
6

जब insert एक std::vector सी ++ मानक में आईएनजी के बाद सभी iterators अमान्य भरोसा दिलाते हैं कि सम्मिलन बिंदु से पहले सभी iterators तक वैध रहेगा के रूप में capacity समाप्त न हो जाए (देखें [ 23.2.4.3/1] या std::vector iterator invalidation)।क्यों std करता :: वेक्टर :: डालने सम्मिलन बिंदु

सम्मिलन बिंदु मान्य होने के बाद इटरेटर को अनुमति देने के पीछे तर्क क्या है (यदि क्षमता समाप्त नहीं हुई है)? बेशक, वे एक अलग तत्व को इंगित करेंगे लेकिन (std::vector के अनुमानित कार्यान्वयन से) इस तरह के एक इटरेटर का उपयोग करना अभी भी संभव होना चाहिए (उदाहरण के लिए इसे अस्वीकार करना या इसे बढ़ाएं)।

उत्तर

3

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

आप सही हैं कि, व्यावहारिक रूप से, यदि आप इस तरह के एक इटरेटर को कम करना चाहते हैं, तो आप किसी भी क्रैशिंग या नाक राक्षसों का अनुभव नहीं कर सकते हैं, लेकिन यह मान्य नहीं है।

+0

आप कहते हैं कि सी ++ मानक डीरफ्रेंसिंग द्वारा ऐसे इटरेटर को अपरिभाषित व्यवहार नहीं होता है? –

+1

@ TobiasBrüll no, C++ मानक द्वारा यह अपरिभाषित (सी ++ मानक द्वारा) व्यवहार का कारण बनता है। सबसे आम अपरिभाषित व्यवहार, यदि क्षमता नहीं बदली जाती है, तो यह है कि आपको वह तत्व मिलता है जो अब आपके ऑफरेटर को वास्तविक अभ्यास में संदर्भित करता है। लेकिन "पुनरावृत्तियों जो वे संदर्भित करते हैं उन्हें बदलते हैं" के बारे में कचरा जोड़ने के बजाय, जो कार्यान्वित किया जाता है और जो मानक को पढ़ने के लिए कठिन बनाते हैं (हे), वे मूल रूप से कहते हैं कि इटरेटर हमेशा एक ही चीज़ का संदर्भ लेते हैं, या अमान्य हो जाते हैं। इस सिद्धांत के सिद्धांत में एक संकलक ऐसा अनुकूलन कर सकता है। – Yakk

+1

@ TobiasBrüll: नहीं, यह अभी भी अपरिभाषित व्यवहार है। इसका मतलब यह नहीं है कि आपको दुर्घटना हो रही है। –

1

वेक्टर नहीं जानता कि कौन से इटरेटर मौजूद हैं। फिर भी सम्मिलित तत्व के बाद तत्वों की स्मृति स्थान बदल गया। इसका अर्थ यह है कि, इटरेटर्स को यह दिखाने के लिए अपडेट किया जाना चाहिए कि परिवर्तन वैध होना चाहिए। लेकिन वेक्टर इस अद्यतन को नहीं कर सकता है, क्योंकि यह नहीं जानता कि कौन से इटरेटर मौजूद हैं।

3

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

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

+0

पुनर्वितरण के साथ यह एक और मुद्दा है। मैं इस मामले के बारे में बात कर रहा था कि पर्याप्त क्षमता शेष थी। –

+0

व्यवहार को निर्धारक और सुसंगत होने की आवश्यकता है। एक सामान्य उपयोग केस यह जानना या देखभाल करना नहीं है कि क्षमता> उपयोग या नहीं। – cdmh

9

आप एक "अमान्य" इटरेटर के बारे में सोच रहे हैं, जो केवल एक ही है जो उपयोग किए जाने पर दुर्घटना को उकसाएगा, लेकिन मानक की परिभाषा व्यापक है। इसमें संभावना है कि इटरेटर अभी भी सुरक्षित रूप से अव्यवस्थित हो सकता है, लेकिन उस तत्व को इंगित नहीं करता है जिस पर यह इंगित करने की उम्मीद है। (यह अवलोकन का एक विशेष मामला है कि "अपरिभाषित व्यवहार" का अर्थ है "आपका प्रोग्राम तुरंत क्रैश हो जाएगा"; इसका अर्थ यह भी हो सकता है कि "आपका प्रोग्राम चुपचाप गलत परिणाम की गणना करेगा" या यहां तक ​​कि "कुछ भी गलत नहीं होगा इस कार्यान्वयन ")

यह प्रदर्शित करने के लिए कारण है कि इस erase साथ कोई समस्या है आसान है:।

#include <vector> 
#include <iostream> 
int main(void) 
{ 
    std::vector<int> a { 0, 1, 2, 3, 4, 4, 6 }; 

    for (auto p = a.begin(); p != a.end(); p++) // THIS IS WRONG 
     if (*p == 4) 
      a.erase(p); 

    for (auto p = a.begin(); p != a.end(); p++) 
     std::cout << ' ' << *p; 

    std::cout << '\n'; 
} 

सी के ++ इस कार्यक्रम क्रैश नहीं करेंगे ठेठ कार्यान्वयन पर, लेकिन यह 0 1 2 3 4 6 प्रिंट के बजाय होगा 0 1 2 3 6 संभवतः इरादा है, क्योंकि एफ को मिटा रहा है irst 4p अमान्य 4 पर इसे आगे बढ़ाकर।

आपके सी ++ कार्यान्वयन में एक विशेष "डीबगिंग" मोड हो सकता है जिसमें यह प्रोग्राम क्रैश होने पर क्रैश करता है। उदाहरण के लिए, जीसीसी 4 के साथ।8:

$ g++ -std=c++11 -W -Wall test.cc && ./a.out 
0 1 2 3 4 6 

लेकिन

$ g++ -std=c++11 -W -Wall -D_GLIBCXX_DEBUG test.cc && ./a.out 
/usr/include/c++/4.8/debug/safe_iterator.h:307:error: attempt to increment 
    a singular iterator. 

Objects involved in the operation: 
iterator "this" @ 0x0x7fff5d659470 { 
type = N11__gnu_debug14_Safe_iteratorIN9__gnu_cxx17__normal_iteratorIPiNSt9__cxx19986vectorIiSaIiEEEEENSt7__debug6vectorIiS6_EEEE (mutable iterator); 
    state = singular; 
    references sequence with type `NSt7__debug6vectorIiSaIiEEE' @ 0x0x7fff5d659470 
} 
Aborted 

समझते हो कि कार्यक्रम अपरिभाषित व्यवहार किसी भी तरह से भड़काती। यह सिर्फ इतना है कि अपरिभाषित व्यवहार के परिणाम डीबगिंग मोड में अधिक नाटकीय हैं।

+0

यह बिल्कुल सवाल है: क्या वह कोड है जिसे आपने मानक अनुरूप सी ++ दिया है (हालांकि यह संभवतः ऐसा नहीं कर सकता है)? या बल्कि, यह मानक अनुरूप क्यों नहीं है? दुर्भाग्य से सी ++ की मेरी मानसिक तस्वीर से पता चलता है कि आपके कोड को आपके द्वारा दिखाए गए आउटपुट को वैध रूप से देना चाहिए। –

+0

@ TobiasBrüll उपरोक्त कोड अपरिभाषित व्यवहार निष्पादित करता है। यदि आपके ऑस्ट्रेलिया की जानकारी को ऑस्ट्रेलिया में ईमेल करने के बाद आपके हार्ड ड्राइव को स्वरूपित किया गया है तो संकलक पूरी तरह से मानक अनुरूप होगा, हालांकि यह सर्वोत्तम संकलक प्रथाओं के अनुरूप नहीं होगा। आउटपुट जैक को निश्चित रूप से मानक द्वारा गारंटी नहीं दी जाती है, लेकिन इसकी अनुमति है *। दूसरी तरफ, 'std :: vector' का विशेष कार्यान्वयन कंपाइलर उपयोग वास्तविक अभ्यास में उपर्युक्त व्यवहार की गारंटी दे सकता है (या तो औपचारिक रूप से, दस्तावेज़ों में (संभावना नहीं), या क्योंकि स्रोत कोड 'std :: vector' है उजागर)। – Yakk

+0

@ TobiasBrüll Yakk सही है। आगे के प्रदर्शनी के लिए संपादन देखें। – zwol

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