जवाबों:
const_iterator
s आपको उन मूल्यों को बदलने की अनुमति नहीं देता है जो वे इंगित करते हैं, नियमित iterator
करते हैं।
C ++ में सभी चीजों के साथ, हमेशा पसंद करें const
, जब तक कि नियमित पुनरावृत्तियों का उपयोग करने का एक अच्छा कारण नहीं है (यानी आप इस तथ्य का उपयोग करना चाहते हैं कि वे const
इंगित करने के लिए मान को बदलना नहीं चाहते हैं)।
उन्हें आत्म-व्याख्यात्मक होना चाहिए। यदि इट्रेटर टाइप 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, उदाहरण के लिए), वह जिस पॉइंट को इंगित करता है उसे बदला नहीं जा सकता है।
const iterater
- बीच में सूक्ष्मता को समझाने के लिए अपग्रेड किया const_iterator
।
Unfortunaty, एसटीएल कंटेनरों के लिए तरीकों का एक बहुत लेता है iterators बजाय const_iterators पैरामीटर के रूप में। इसलिए यदि आपके पास एक const_iterator है , तो आप यह नहीं कह सकते हैं कि "तत्व से पहले एक तत्व डालें जो इस पुनरावृत्त को इंगित करता है" (ऐसा कहना वैचारिक रूप से एक कास्ट उल्लंघन नहीं है, मेरी राय में)। यदि आप ऐसा चाहते हैं, तो भी, आपको इसे std :: अग्रिम () या बूस्ट :: next () का उपयोग करके एक नॉन-कास्ट इटरेटर में बदलना होगा । उदाहरण के लिए। बढ़ावा देना :: अगला (कंटेनर . begin (), एसटीडी: दूरी (कंटेनर . begin (), the_const_iterator_we_want_to_unconst) । यदि कंटेनर एक std :: सूची है , तो उस कॉल के लिए चलने का समय O (n) होगा ।
तो ऐसा करने के लिए जहां भी "तार्किक" हो, वहां कास्ट जोड़ने का सार्वभौमिक नियम कम सार्वभौमिक है जब यह एसटीएल कंटेनरों की बात आती है।
हालांकि, बूस्ट कंटेनर कांस्टेंटाइटर लेते हैं (उदाहरण के लिए। बढ़ावा :: unordered_map :: erase ())। इसलिए जब आप बूस्ट कंटेनरों का उपयोग करते हैं तो आप "कॉन्स्ट एग्रेसिव" हो सकते हैं। वैसे, क्या किसी को पता है कि एसटीएल कंटेनर कब या कब ठीक किए जाएंगे?
vector
और deque
, एक तत्व सम्मिलित करना सभी मौजूदा पुनरावृत्तियों को अमान्य करता है, जो बहुत नहीं है const
। लेकिन मैं आपकी बात देख रहा हूं। इस तरह के संचालन को कंटेनर const
-नेस द्वारा संरक्षित किया जाता है , न कि पुनरावृत्तियों। और मुझे आश्चर्य है कि मानक कंटेनर इंटरफ़ेस में कॉन्स्ट-टू-नॉनकॉस्ट इटेरेटर रूपांतरण फ़ंक्शन क्यों नहीं है।
int const * foo;
int * const foo;
और int const * const foo;
सभी तीन वैध और उपयोगी हैं, प्रत्येक अपने तरीके से। std::vector<int> const bar
दूसरे के समान ही होना चाहिए, लेकिन दुर्भाग्य से अक्सर तीसरे की तरह व्यवहार किया जाता है। समस्या का मूल कारण यह है कि हम यह नहीं कह सकते कि std::vector<int const> bar;
जब int const *foo;
किसी वेक्टर में समान प्रभाव प्राप्त करने का कोई तरीका नहीं है ।
न्यूनतम रननीय उदाहरण
नॉन-कास्ट पुनरावृत्तियों आपको यह इंगित करने की अनुमति देते हैं कि वे क्या इंगित करते हैं:
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) {}
};
const
this
const बनाता है , जो this->v
const बनाता है ।
आप आमतौर पर इसके बारे में भूल सकते हैं 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
: जब भी आप उनका उपयोग कर सकते हैं (जब आपको उनके साथ कंटेनर को संशोधित करने की आवश्यकता नहीं है) कांस्ट पुनरावृत्तियों को प्राथमिकता दें, तो संशोधित किए बिना आपके पढ़ने के इरादे को बेहतर बनाने के लिए।
(जैसा कि अन्य लोगों ने कहा है) const_iterator आपको उन तत्वों को संशोधित करने की अनुमति नहीं देता है जिनसे यह इंगित करता है, यह कॉन्स्ट क्लास विधियों के अंदर उपयोगी है। यह आपको अपना इरादा व्यक्त करने की भी अनुमति देता है।
ठीक है, मैं इसे बहुत सरल उदाहरण के साथ समझाता हूं, बिना निरंतर चलने वाले का उपयोग किए बिना पहले विचार करें कि हमारे पास यादृच्छिक पूर्णांक संग्रह "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;
जैसा कि संग्रह के अंदर डेटा लिखने / संपादित करने के लिए देखा जा सकता है सामान्य पुनरावृत्त का उपयोग किया जाता है, लेकिन पढ़ने के उद्देश्य से निरंतर पुनरावृत्ति का उपयोग किया गया है। यदि आप लूप के लिए पहले में लगातार चलने वाले का उपयोग करने की कोशिश करते हैं तो आपको त्रुटि मिलेगी। एक अंगूठे के नियम के रूप में संग्रह के अंदर डेटा पढ़ने के लिए निरंतर पुनरावृत्ति का उपयोग करें।