जवाबों:
यह काफी सरल है। कहो मेरे पास एक वेक्टर है:
std::vector<int> vec;
मैं इसे कुछ आंकड़ों से भरता हूं। फिर मैं इसके लिए कुछ पुनरावृत्तियों को प्राप्त करना चाहता हूं। शायद उनके आसपास से गुजर जाए। हो सकता है std::for_each:
std::for_each(vec.begin(), vec.end(), SomeFunctor());
C ++ 03 में, यह प्राप्त पैरामीटर SomeFunctorको संशोधित करने में सक्षम होने के लिए स्वतंत्र था । ज़रूर, SomeFunctorइसके पैरामीटर को मान या द्वारा ले सकता है const&, लेकिन यह सुनिश्चित करने का कोई तरीका नहीं है कि यह करता है। इस तरह मूर्खतापूर्ण कुछ किए बिना नहीं:
const std::vector<int> &vec_ref = vec;
std::for_each(vec_ref.begin(), vec_ref.end(), SomeFunctor());
अब, हम परिचय देते हैं cbegin/cend:
std::for_each(vec.cbegin(), vec.cend(), SomeFunctor());
अब, हमारे पास सिंटैक्टिक आश्वासन हैं जो SomeFunctorवेक्टर के तत्वों (एक कास्ट-कास्ट के बिना, बिल्कुल) को संशोधित नहीं कर सकते हैं। हम स्पष्ट रूप से प्राप्त करते हैं const_iterator, और इसलिए SomeFunctor::operator()इसके साथ बुलाया जाएगा const int &। यदि यह इसे पैरामीटर के रूप में लेता है int &, तो C ++ कंपाइलर त्रुटि जारी करेगा।
C ++ 17 में इस समस्या का एक और अधिक सुंदर समाधान है std::as_const:। रेंज-आधारित का उपयोग करते समय, कम से कम यह सुरुचिपूर्ण है for:
for(auto &item : std::as_const(vec))
यह बस const&प्रदान की गई वस्तु के लिए एक रिटर्न देता है ।
std::cbegin/cendजिस तरह से std::begin/std::endमौजूद हैं, कोई मुफ्त कार्य नहीं हैं। यह समिति द्वारा एक निरीक्षण था। यदि वे कार्य मौजूद थे, तो आमतौर पर उनका उपयोग करने का तरीका होगा।
std::cbegin/cendC ++ 14 में जोड़ा जाएगा। देखें en.cppreference.com/w/cpp/iterator/begin
for(auto &item : std::as_const(vec))बराबर है for(const auto &item : vec)?
constसंदर्भ पर रखकर संशोधित नहीं किया जाएगा । निकोल के कंटेनर को कास्ट के रूप में देखा गया है, इसलिए autoएक constसंदर्भ को घटाता है । IMO auto const& itemआसान और स्पष्ट है। यह स्पष्ट नहीं है कि std::as_const()यहाँ अच्छा क्यों है; मैं देख सकता हूँ कि यह उपयोगी होगा जब कुछ गैर- constजेनेरिक कोड पास करने के लिए जहां हम उस प्रकार को नियंत्रित नहीं कर सकते हैं जो इस्तेमाल किया जाता है, लेकिन रेंज- के साथ for, हम कर सकते हैं, इसलिए ऐसा लगता है जैसे मेरे लिए वहां जोड़ा गया शोर है।
निकोल बोलस ने अपने उत्तर में जो कहा, उससे परे नए autoकीवर्ड पर विचार करें :
auto iterator = container.begin();
इसके साथ auto, यह सुनिश्चित करने का कोई तरीका नहीं है कि begin()एक निरंतर ऑपरेटर को एक गैर-स्थिर कंटेनर संदर्भ के लिए लौटाया जाए। तो अब आप करते हैं:
auto const_iterator = container.cbegin();
const_iteratorबस एक और पहचानकर्ता है। न तो संस्करण सामान्य सदस्य टाइपडिफ्स की खोज का उपयोग करता है decltype(container)::iteratorया decltype(container)::const_iterator।
const_iteratorसाथ प्राप्त करें: ऑब्जेक्ट तर्क को अर्हता प्राप्त करने के लिए autoकहा जाता है एक सहायक फ़ंक्शन टेम्पलेट लिखें make_const।
इसे एक व्यावहारिक usecase के रूप में लें
void SomeClass::f(const vector<int>& a) {
auto it = someNonConstMemberVector.begin();
...
it = a.begin();
...
}
असाइनमेंट विफल हो जाता है क्योंकि itएक नॉनस्टॉक इटेटर है। यदि आप शुरू में केगिन का उपयोग करते थे, तो इट्रेटर का सही प्रकार होता।
से http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1674.pdf :
ताकि एक प्रोग्रामर सीधे नॉन-कॉस्ट कंटेनर से भी एक const_iterator प्राप्त कर सके
उन्होंने इसका उदाहरण दिया
vector<MyType> v;
// fill v ...
typedef vector<MyType>::iterator iter;
for( iter it = v.begin(); it != v.end(); ++it ) {
// use *it ...
}
हालांकि, जब एक कंटेनर ट्रावर्सल केवल निरीक्षण के लिए अभिप्रेत है, तो संकलक का उपयोग करने के लिए एक आम तौर पर पसंदीदा अभ्यास है, ताकि कंपाइलर को कांस्ट-शुद्धता उल्लंघन का निदान करने की अनुमति मिल सके
नोट वर्किंग पेपर भी एडाप्टर टेम्पलेट्स का उल्लेख है, कि अब के रूप में अंतिम रूप दे दिया गया है कि std::begin()और std::end()और वह भी देशी सरणियों के साथ काम करते हैं। संबंधित std::cbegin()और std::cend()इस समय के रूप में गायब हैं, लेकिन उन्हें भी जोड़ा जा सकता है।
बस इस सवाल पर लड़खड़ा गया ... मुझे पता है कि यह बहुत बुरा जवाब है और यह सिर्फ एक पक्ष नोड है ...
auto const it = container.begin() फिर एक अलग प्रकार है auto it = container.cbegin()
के लिए अंतर int[5](पॉइंटर का उपयोग करके, जो मुझे पता है कि शुरुआत विधि नहीं है, लेकिन अच्छी तरह से अंतर दिखाएं ... लेकिन सी + + 14 के लिए काम करेंगे std::cbegin()और std::cend(), जो अनिवार्य रूप से एक का उपयोग करना चाहिए जब वह यहां है ...)
int numbers = array[7];
const auto it = begin(numbers); // type is int* const -> pointer is const
auto it = cbegin(numbers); // type is int const* -> value is const
iteratorऔर const_iteratorइनहेरिटेंस संबंध और एक अंतर्निहित रूपांतरण तब होता है जब अन्य प्रकार के साथ तुलना या असाइन किया जाता है।
class T {} MyT1, MyT2, MyT3;
std::vector<T> MyVector = {MyT1, MyT2, MyT3};
for (std::vector<T>::const_iterator it=MyVector.begin(); it!=MyVector.end(); ++it)
{
// ...
}
उपयोग करने cbegin()और cend()इस मामले में प्रदर्शन में वृद्धि होगी।
for (std::vector<T>::const_iterator it=MyVector.cbegin(); it!=MyVector.cend(); ++it)
{
// ...
}
constमुख्य लाभ प्रदर्शन है (जो यह नहीं है: यह शब्दार्थ रूप से सही और सुरक्षित कोड है)। लेकिन, जब आपके पास एक बिंदु होता है, (ए) autoएक गैर-मुद्दा बनाता है; (बी) प्रदर्शन के बारे में बात करने में, आपको एक मुख्य बात याद आती है जो आपको यहाँ करनी चाहिए थी: लूप endके इनिट-कंडीशन में इसकी एक कॉपी घोषित करके इटरेटर को कैश करें for, और एक नई कॉपी प्राप्त करने के बजाय उसकी तुलना करें हर पुनरावृत्ति के लिए मूल्य। इससे आपकी बात बेहतर होगी। : P
constनिश्चित रूप से बेहतर प्रदर्शन को प्राप्त करने में मदद कर सकता है, न कि constकीवर्ड में कुछ जादू के कारण, बल्कि इसलिए कि कंपाइलर कुछ अनुकूलन कर सकता है यदि यह जानता है कि डेटा संशोधित नहीं किया जाएगा, जो अन्यथा संभव नहीं होगा। चेक इस बिट इस का लाइव उदाहरण के लिए एक जैसन टर्नर की बात से।
constप्रदर्शन लाभ के लिए नेतृत्व कर सकते हैं (लगभग अप्रत्यक्ष रूप से); यदि कोई व्यक्ति इसे पढ़ता है तो मुझे लगता है कि "मैं यह जोड़ने की जहमत नहीं उठाऊंगा constकि उत्पन्न कोड किसी भी तरह से प्रभावित नहीं होता है", जो कि सच नहीं है।
इसकी सरल, cbegin एक निरंतर पुनरावृत्ति देता है जहाँ से एक पुनरावृत्तिक शुरू होता है
बेहतर समझ के लिए दो परिदृश्यों को यहाँ ले जाने दें
दृष्टांत 1 :
#include <iostream>
using namespace std;
#include <vector>
int main(int argc, char const *argv[])
{
std::vector<int> v;
for (int i = 1; i < 6; ++i)
{
/* code */
v.push_back(i);
}
for(auto i = v.begin();i< v.end();i++){
*i = *i + 5;
}
for (auto i = v.begin();i < v.end();i++){
cout<<*i<<" ";
}
return 0;
}
यह चलेगा क्योंकि यहाँ पुनरावृत्ति i स्थिर नहीं है और इसे 5 से बढ़ाया जा सकता है
अब चलो cbegin का उपयोग करें और उन्हें लगातार चलने वाले परिदृश्य के रूप में दर्शाते हुए देखें - 2:
#include <iostream>
using namespace std;
#include <vector>
int main(int argc, char const *argv[])
{
std::vector<int> v;
for (int i = 1; i < 6; ++i)
{
/* code */
v.push_back(i);
}
for(auto i = v.cbegin();i< v.cend();i++){
*i = *i + 5;
}
for (auto i = v.begin();i < v.end();i++){
cout<<*i<<" ";
}
return 0;
}
यह काम नहीं करने वाला है, क्योंकि आप कैबिन और सेंड का उपयोग करके मूल्य को अपडेट नहीं कर सकते हैं जो निरंतर पुनरावृत्त रिटर्न देता है