C ++ STL में const_iterator और नॉन-कास्ट इटरेटर के बीच क्या अंतर है?


139

एक const_iteratorऔर एक के बीच अंतर क्या है iteratorऔर आप एक दूसरे पर कहां उपयोग करेंगे?


1
वैसे, const_iterator नाम ऐसा लगता है जैसे कि इट्रैक्टर, const है, जबकि यह इट्रेटर जिस चीज़ की ओर इशारा करता है, वह वास्तविक const है।
कथास्केडोबा

जवाबों:


124

const_iterators आपको उन मूल्यों को बदलने की अनुमति नहीं देता है जो वे इंगित करते हैं, नियमित iteratorकरते हैं।

C ++ में सभी चीजों के साथ, हमेशा पसंद करें const, जब तक कि नियमित पुनरावृत्तियों का उपयोग करने का एक अच्छा कारण नहीं है (यानी आप इस तथ्य का उपयोग करना चाहते हैं कि वे constइंगित करने के लिए मान को बदलना नहीं चाहते हैं)।


8
एक आदर्श दुनिया में ऐसा ही होगा। लेकिन C ++ कास्ट के साथ केवल उतना ही अच्छा है जितना उस व्यक्ति ने जो कोड लिखा है :(
JaredPar

उत्परिवर्तन एक बहुत अच्छे कारण के लिए मौजूद है। इसका उपयोग शायद ही कभी किया जाता है, और Google कोड खोज को देखते हुए, उचित उपयोग का उचित प्रतिशत प्रतीत होता है। कीवर्ड एक बहुत शक्तिशाली अनुकूलन उपकरण है, और इसे हटाने यह स्थिरांक-शुद्धता (सुधार होगा की तरह नहीं है coughpointerscoughandcoughreferencescough )
coppro

2
एक शक्तिशाली हैक की तरह। सभी उदाहरणों में से मैंने कभी भी 'उत्परिवर्तित' कीवर्ड के उपयोग के बारे में देखा है, लेकिन सभी एक सटीक संकेतक था कि कोड खराब लिखा गया था और दोषों के आसपास पहुंचने के लिए एक हैक के रूप में उत्परिवर्ती की आवश्यकता थी।
जॉन डिब्लिंग

7
इसका वैध उपयोग होता है, जैसे एक कांस्ट क्लास के भीतर एक लंबी गणना के परिणामों को कैशिंग करना। दूसरी ओर, यह बहुत ही एकमात्र समय है जब मैंने लगभग बीस वर्षों के सी ++ विकास में एक परस्पर उपयोग किया है।
हेड गीक

Const_iterator का उपयोग करने के लिए एक सामान्य उदाहरण तब होगा जब
इट्रेटर

40

उन्हें आत्म-व्याख्यात्मक होना चाहिए। यदि इट्रेटर टाइप T के एक तत्व को इंगित करता है, तो const_iterator टाइप 'const T' के एक तत्व को इंगित करता है।

यह मूल रूप से सूचक प्रकारों के बराबर है:

T* // A non-const iterator to a non-const element. Corresponds to std::vector<T>::iterator
T* const // A const iterator to a non-const element. Corresponds to const std::vector<T>::iterator
const T* // A non-const iterator to a const element. Corresponds to std::vector<T>::const_iterator

एक const itter हमेशा एक ही तत्व को इंगित करता है, इसलिए itter स्वयं const है। लेकिन वह जिस तत्व की ओर इशारा करता है, उसे कब्ज नहीं होना चाहिए, इसलिए वह जिस तत्व को इंगित करता है उसे बदला जा सकता है। एक const_iterator एक इटरेटर है जो एक कॉस्ट एलिमेंट को इंगित करता है, इसलिए जबकि इटरेटर को ही अपडेट किया जा सकता है (incremented या decremented, उदाहरण के लिए), वह जिस पॉइंट को इंगित करता है उसे बदला नहीं जा सकता है।


1
"एक const itter हमेशा एक ही तत्व को इंगित करता है," यह गलत है।
जॉन डिब्लिंग

2
ऐसा कैसे? गायब अंडरस्कोर पर ध्यान दें। मैं प्रकार const std :: वेक्टर <T> :: itter with std :: वेक्टर <T> :: const_iterator के एक चर के विपरीत हूं। पूर्व के मामले में, इट्रेटर ही कॉन्स्टेबल है, इसलिए इसे संशोधित नहीं किया जा सकता है, लेकिन जिस तत्व को संदर्भित करता है उसे स्वतंत्र रूप से संशोधित किया जा सकता है।
:१al

4
ओह समझा। हाँ मैं गायब अंडरस्कोर याद किया।
जॉन डिब्लिंग

3
@ जॉनडब्लिंग ने बीच const iterater- बीच में सूक्ष्मता को समझाने के लिए अपग्रेड किया const_iterator
लीजेंड 2k

8

Unfortunaty, एसटीएल कंटेनरों के लिए तरीकों का एक बहुत लेता है iterators बजाय const_iterators पैरामीटर के रूप में। इसलिए यदि आपके पास एक const_iterator है , तो आप यह नहीं कह सकते हैं कि "तत्व से पहले एक तत्व डालें जो इस पुनरावृत्त को इंगित करता है" (ऐसा कहना वैचारिक रूप से एक कास्ट उल्लंघन नहीं है, मेरी राय में)। यदि आप ऐसा चाहते हैं, तो भी, आपको इसे std :: अग्रिम () या बूस्ट :: next () का उपयोग करके एक नॉन-कास्ट इटरेटर में बदलना होगा । उदाहरण के लिए। बढ़ावा देना :: अगला (कंटेनर . begin (), एसटीडी: दूरी (कंटेनर . begin (), the_const_iterator_we_want_to_unconst) । यदि कंटेनर एक std :: सूची है , तो उस कॉल के लिए चलने का समय O (n) होगा

तो ऐसा करने के लिए जहां भी "तार्किक" हो, वहां कास्ट जोड़ने का सार्वभौमिक नियम कम सार्वभौमिक है जब यह एसटीएल कंटेनरों की बात आती है।

हालांकि, बूस्ट कंटेनर कांस्टेंटाइटर लेते हैं (उदाहरण के लिए। बढ़ावा :: unordered_map :: erase ())। इसलिए जब आप बूस्ट कंटेनरों का उपयोग करते हैं तो आप "कॉन्स्ट एग्रेसिव" हो सकते हैं। वैसे, क्या किसी को पता है कि एसटीएल कंटेनर कब या कब ठीक किए जाएंगे?


1
यह एक राय का विषय हो सकता है। के मामले में vectorऔर deque, एक तत्व सम्मिलित करना सभी मौजूदा पुनरावृत्तियों को अमान्य करता है, जो बहुत नहीं है const। लेकिन मैं आपकी बात देख रहा हूं। इस तरह के संचालन को कंटेनर const-नेस द्वारा संरक्षित किया जाता है , न कि पुनरावृत्तियों। और मुझे आश्चर्य है कि मानक कंटेनर इंटरफ़ेस में कॉन्स्ट-टू-नॉनकॉस्ट इटेरेटर रूपांतरण फ़ंक्शन क्यों नहीं है।
पोटाटोस्वाटर

आप सही Potatoswatter हैं, मैं स्पष्ट करने के लिए कर रहा हूँ, यह रैंडम एक्सेस कंटेनरों के लिए राय और की बात है container.begin () + (the_const_iterator_we_want_to_unconst - container.begin ()) है हे (1) वैसे भी। मुझे यह भी आश्चर्य है कि गैर-यादृच्छिक एक्सेस कंटेनरों के लिए कोई रूपांतरण फ़ंक्शन क्यों नहीं है, लेकिन शायद एक अच्छा कारण है? क्या आप जानते हैं कि कुछ कारण है कि गैर-यादृच्छिक एक्सेस कंटेनरों के लिए फ़ंक्शंस const_iterators नहीं लेते हैं ?
मैग्नस एंडर्मो

"ऐसा कहना वैचारिक रूप से एक कास्ट उल्लंघन नहीं है, मेरी राय में" - यह एक बहुत ही दिलचस्प टिप्पणी है, मेरे पास विषय पर निम्नलिखित विचार हैं। सरल बिंदुओं के साथ, कोई भी कह सकता है int const * foo; int * const foo;और int const * const foo;सभी तीन वैध और उपयोगी हैं, प्रत्येक अपने तरीके से। std::vector<int> const barदूसरे के समान ही होना चाहिए, लेकिन दुर्भाग्य से अक्सर तीसरे की तरह व्यवहार किया जाता है। समस्या का मूल कारण यह है कि हम यह नहीं कह सकते कि std::vector<int const> bar;जब int const *foo;किसी वेक्टर में समान प्रभाव प्राप्त करने का कोई तरीका नहीं है ।
dgnuff

5

उपयोग const_iterator जब भी आप उपयोग कर सकते हैं इटरेटर जब आप कोई अन्य विकल्प नहीं है।


4

न्यूनतम रननीय उदाहरण

नॉन-कास्ट पुनरावृत्तियों आपको यह इंगित करने की अनुमति देते हैं कि वे क्या इंगित करते हैं:

std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
*it = 1;
assert(v[0] == 1);

कांस्ट पुनरावृत्तियों नहीं:

const std::vector<int> v{0};
std::vector<int>::const_iterator cit = v.begin();
// Compile time error: cannot modify container with const_iterator.
//*cit = 1;

ऊपर दिखाए गए के रूप में, v.begin()है constअतिभारित या नहीं और फिर iteratorया const_iteratorकंटेनर चर का स्थिरांक सत्ता पर निर्भर करता है:

एक आम मामला जहां const_iteratorपॉप अप होता है जब thisएक constविधि के अंदर प्रयोग किया जाता है :

class C {
    public:
        std::vector<int> v;
        void f() const {
            std::vector<int>::const_iterator it = this->v.begin();
        }
        void g(std::vector<int>::const_iterator& it) {}
};

constthisconst बनाता है , जो this->vconst बनाता है ।

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

कॉन्स्ट और नॉन-कॉस्ट की तरह, आप नॉन-कॉस्ट से कॉन्स में आसानी से परिवर्तित कर सकते हैं, लेकिन आस-पास के अन्य तरीके से नहीं:

std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();

// non-const to const.
std::vector<int>::const_iterator cit = it;

// Compile time error: cannot modify container with const_iterator.
//*cit = 1;

// Compile time error: no conversion from const to no-const.
//it = ci1;

जो एक का उपयोग करने के लिए: const intबनाम के अनुरूप int: जब भी आप उनका उपयोग कर सकते हैं (जब आपको उनके साथ कंटेनर को संशोधित करने की आवश्यकता नहीं है) कांस्ट पुनरावृत्तियों को प्राथमिकता दें, तो संशोधित किए बिना आपके पढ़ने के इरादे को बेहतर बनाने के लिए।


0

(जैसा कि अन्य लोगों ने कहा है) const_iterator आपको उन तत्वों को संशोधित करने की अनुमति नहीं देता है जिनसे यह इंगित करता है, यह कॉन्स्ट क्लास विधियों के अंदर उपयोगी है। यह आपको अपना इरादा व्यक्त करने की भी अनुमति देता है।


0

ठीक है, मैं इसे बहुत सरल उदाहरण के साथ समझाता हूं, बिना निरंतर चलने वाले का उपयोग किए बिना पहले विचार करें कि हमारे पास यादृच्छिक पूर्णांक संग्रह "randomData" का संग्रह है

    for(vector<int>::iterator i = randomData.begin() ; i != randomData.end() ; ++i)*i = 0;
for(vector<int>::const_iterator i = randomData.begin() ; i!= randomData.end() ; ++i)cout << *i;

जैसा कि संग्रह के अंदर डेटा लिखने / संपादित करने के लिए देखा जा सकता है सामान्य पुनरावृत्त का उपयोग किया जाता है, लेकिन पढ़ने के उद्देश्य से निरंतर पुनरावृत्ति का उपयोग किया गया है। यदि आप लूप के लिए पहले में लगातार चलने वाले का उपयोग करने की कोशिश करते हैं तो आपको त्रुटि मिलेगी। एक अंगूठे के नियम के रूप में संग्रह के अंदर डेटा पढ़ने के लिए निरंतर पुनरावृत्ति का उपयोग करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.